/*++ Copyright (c) 1998-1999, Microsoft Corporation Module Name: pidgen.cpp Abstract: contains PIDGen entrypoint to pidgen dll --*/ // v-jhark 07-26-99 added support for OEM RPC/MPC: // for OEM if lstrRpc is not NULL, it's used as the first // 5 characters fo the PID (replacing the Julian Date) // // PIDGen.cpp #define WINDOWS_LEAN_AND_MEAN // faster compile #include #if defined(WIN32) || defined(_WIN32) #include #include "hardware.h" #else #include #include #include #include "..\..\inc\tchar.h" extern "C" extern WORD _C000H; extern "C" extern WORD _F000H; #endif #include "..\inc\DigPid.h" #include "..\inc\shortsig.h" #include "pidgen.h" #include "util.h" #include "crc-32.h" #if TESTING_CODE #include #endif #include "range.h" #define MIN(a,b) (((a)<=(b))?(a):(b)) typedef struct { DWORD dwKeyIdx; BYTE abPublicKey[1]; } BINKEY, *PBINKEY, FAR *LPBINKEY; // returns the count of ch characters in pstr int StrCountCharA(char *pstr, char ch) { int iCnt = 0; while ('\0' != *pstr) { if (ch == *pstr) { ++iCnt; } ++pstr; } return iCnt; } #if defined(WIN32) || defined(_WIN32) int StrCountCharW(LPWSTR pstr, WCHAR ch) { int iCnt = 0; while (L'\0' != *pstr) { if (ch == *pstr) { ++iCnt; } ++pstr; } return iCnt; } #endif // defined(WIN32) || defined(_WIN32) #if defined(UNICODE) || defined(_UNICODE) #define StrCountChar StrCountCharW #else #define StrCountChar StrCountCharA #endif // DecodeProdKey is given a string of encoded chars and returns the // 31-bit data payload or INVALID_PID if there is an error or failure // to validate. DWORD DecodeProdKey( LPSTR lpstrEncodedChars, // ptr to 25-character secure CD-Key LPBYTE pbPublicKey, // pointer to the public key LONG cbPublicKey, // size of the public key in bytes LPSTR lpstrDigits, // custom achDigits array LPBYTE pbBinCdKey, // if non-NULL return binary version of secure CD-Key int cbBinCdKey) { BOOL fOk = TRUE; DWORD dwBinData = INVALID_PID; const int iBase = 24; // 64 bytes is enough space to decode 111 encoded characters (when iBase is 24) BYTE abDecodedBytes[64] = {0}; int iDecodedBytes; // index int iDecodedBytesMax = 0; // index of highest byte used const int iDecodedPidBitCnt = 31; BYTE abDecodedPid[iDecodedPidBitCnt/8 + (0 != iDecodedPidBitCnt/8)] = {0}; // Number of bits that can be encoded in 1000 base 24 digits // 1000 * log(24, 2) const int iBitsPerKChar = 4585; char achDigits[iBase+1] = "BCDFGHJKMPQRTVWXY2346789"; int iDigits; // index int iBitCnt = (int)(((long)(lstrlenA(lpstrEncodedChars) - StrCountCharA(lpstrEncodedChars, '-') ) * iBitsPerKChar) / 1000); int iByteCnt = iBitCnt/8 + (0 != iBitCnt%8); int iSigBitCnt = iBitCnt - iDecodedPidBitCnt; int iSigByteCnt = iSigBitCnt/8 + (0 != iSigBitCnt%8); if (NULL == lpstrDigits) { lpstrDigits = achDigits; } else { fOk = (lstrlenA(achDigits) == lstrlenA(lpstrDigits)); if (fOk) { StrUpperA(lpstrDigits); } } // We requie at least 25 input characters to leave enough bits for the signature // and we make sure we're not going to overrun our buffer if (fOk && 25 <= lstrlenA(lpstrEncodedChars) && iByteCnt < sizeof(abDecodedBytes)) { StrUpperA(lpstrEncodedChars); // first we fill abDecodedBytes with the binary data LPCSTR lpstrEncodedCharsCurr = lpstrEncodedChars; char chCurEncoded = *lpstrEncodedCharsCurr; while (fOk && TEXT('\0') != chCurEncoded) { // find the character in the list if ('-' != chCurEncoded) // we skip any dashes in the input string { iDigits = 0; while (lpstrDigits[iDigits] != chCurEncoded && TEXT('\0') != lpstrDigits[iDigits]) { ++iDigits; } if (TEXT('\0') == lpstrDigits[iDigits]) { fOk = FALSE; } else { iDecodedBytes = 0; unsigned int i = (unsigned int)iDigits; while (iDecodedBytes <= iDecodedBytesMax) { i += iBase * abDecodedBytes[iDecodedBytes]; abDecodedBytes[iDecodedBytes] = (unsigned char)i; i /= 256; ++iDecodedBytes; } if (i != 0) { if (iDecodedBytes < sizeof(abDecodedBytes)) { abDecodedBytes[iDecodedBytes] = (unsigned char)i; iDecodedBytesMax = iDecodedBytes; } else { // How'd we get here? Didn't we check the byte length // before we started the outer loop? We did check *A* // byte length, but it was based on the maximum number // of full bits that could be encoded in riEncodedChars // (given it's length and iByteCnt) but not all values of // riEncodedChars will fit into that many bits. What we // have here is an invalid value fOk = FALSE; } } } } ++lpstrEncodedCharsCurr; chCurEncoded = *lpstrEncodedCharsCurr; } if (fOk) { // at this point abDecodedBytes is filled with the binary data // if the caller wants it, return the binary representation if (NULL != pbBinCdKey && 0 < cbBinCdKey) { ZeroMemory(pbBinCdKey, cbBinCdKey); CopyMemory(pbBinCdKey, abDecodedBytes, MIN((int)cbBinCdKey, sizeof(abDecodedBytes))); } // separate the 31 bit pid that is sitting in the low 31 bits abDecodedPid[0] = abDecodedBytes[0]; abDecodedPid[1] = abDecodedBytes[1]; abDecodedPid[2] = abDecodedBytes[2]; abDecodedPid[3] = abDecodedBytes[3] & 0x7F; // shift the signature down 31 bits in abDecodedBytes int iDecodedBytesMaxOld = iDecodedBytesMax; iDecodedBytesMax -= 3; if (iDecodedBytesMax < 0) { iDecodedBytesMax = 0; } iDecodedBytes = 0; while (iDecodedBytes <= iDecodedBytesMax) { abDecodedBytes[iDecodedBytes] = (unsigned char) ((abDecodedBytes[iDecodedBytes+3] >> 7) | (abDecodedBytes[iDecodedBytes+4] << 1)); ++iDecodedBytes; } while (iDecodedBytes <= iDecodedBytesMaxOld) { abDecodedBytes[iDecodedBytes] = 0; ++iDecodedBytes; } if (0 == abDecodedBytes[iDecodedBytesMax] && 0 < iDecodedBytesMax) { --iDecodedBytesMax; } LONG cbPrivate = 0; LONG cbPublic = 0; fOk = SS_OK == CryptGetKeyLens( iSigBitCnt, // [IN] count of bits in Sig &cbPrivate, // [OUT] ptr to number of bytes in the private key &cbPublic); // [OUT] ptr to number of bytes in the public key fOk = fOk && (cbPublic == cbPublicKey); fOk = fOk && (SS_OK == CryptVerifySig( sizeof(abDecodedPid), // [IN] number of bytes in message abDecodedPid, // [IN] binary message to sign cbPublicKey, // [IN] number of bytes in public key (from CryptGetKeyLens) pbPublicKey, // [IN] the generated public key (from CryptKeyGen) iSigBitCnt, // [IN] the number of bits in the sig abDecodedBytes)); // [IN] the digital signature (from CryptSign) } if (fOk) { // verified the signature. Now we need to return the binary sequence. // the following line provides immunity from byte order dwBinData = (DWORD)abDecodedPid[0] * 0x00000001 + (DWORD)abDecodedPid[1] * 0x00000100 + (DWORD)abDecodedPid[2] * 0x00010000 + (DWORD)abDecodedPid[3] * 0x01000000; dwBinData &= 0x7fffffff; } } return dwBinData; } // Check site code exclusion list to see if this seq is excluded // Users can define ranges as well to exclude the keys from valid key ranges typedef struct { DWORD dwSeqStart; DWORD dwSeqEnd; } BLOCK_SEQ_RANGE; static BOOL IsSeqExcluded(DWORD dwSeq) { BLOCK_SEQ_RANGE aExclusionList[]={ {640200176,640200176}, // Mexico VL key {640000035,640000035}, // Intel VL Key #ifdef WINXP_SPx_RTM { 2000000, 3999999}, // XPSP Beta Product keys #endif //WINXP_SPx_RTM }; // check for excluded site codes // Now there are two types of number on the exclusion list: // // 1. Numbers less than 1000 (three digit (or less) numbers) are // considered site codes and are matched to the first three // digits of the 9 digit sequence number. // // 2. Numbers greater then or equal to 1000 are considered // sequence numbers and are matched against the full 9 digit // sequence number. BOOL fExcluded = FALSE; DWORD dwSeq1 = dwSeq / 1000000; // ChannelID, a.k.a. Site Code DWORD dwEsclCount = sizeof(aExclusionList)/sizeof(aExclusionList[0]); while (!fExcluded && dwEsclCount) { --dwEsclCount; if (1000 > aExclusionList[dwEsclCount].dwSeqStart) { //sitecode (channelID) exclusion if (dwSeq1 >= aExclusionList[dwEsclCount].dwSeqStart && dwSeq1 <= aExclusionList[dwEsclCount].dwSeqEnd) fExcluded = TRUE; } else { // channelID+seq# exclusion if (dwSeq >= aExclusionList[dwEsclCount].dwSeqStart && dwSeq <= aExclusionList[dwEsclCount].dwSeqEnd) fExcluded = TRUE; } } return fExcluded; } extern "C" DWORD STDAPICALLTYPE PIDGenRc( LPSTR lpstrSecureCdKey, // [IN] 25-character Secure CD-Key (gets U-Cased) LPCSTR lpstrRpc, // [IN] 5-character Release Product Code LPCSTR lpstrSku, // [IN] Stock Keeping Unit (formatted like 123-12345) LPCSTR lpstrOemId, // [IN] 4-character OEM ID or NULL LPSTR lpstrLocal24, // [IN] 24-character ordered set to use for decode base conversion or NULL for default set (gets U-Cased) LPBYTE lpbPublicKey, // [IN] pointer to optional public key or NULL DWORD dwcbPublicKey, // [IN] byte length of optional public key DWORD dwKeyIdx, // [IN] key pair index optional public key BOOL fOem, // [IN] is this an OEM install? LPSTR lpstrPid2, // [OUT] PID 2.0, pass in ptr to 24 character array LPBYTE lpbPid3, // [OUT] pointer to binary PID3 buffer. First DWORD is the length LPDWORD lpdwSeq, // [OUT] optional ptr to sequence number (can be NULL) LPBOOL pfCCP, // [OUT] optional ptr to Compliance Checking flag (can be NULL) LPBOOL pfPSS) // [OUT] optional ptr to 'PSS Assigned' flag (can be NULL) { DWORD dwRet = pgeSuccess; LPDIGITALPID pdpid = (LPDIGITALPID)lpbPid3; BYTE abBinCdKey[sizeof(pdpid->abCdKey)] = {0}; if (NULL == lpstrSecureCdKey) { dwRet = pgeProductKeyNull; } else if (25 != lstrlenA(lpstrSecureCdKey) - StrCountCharA(lpstrSecureCdKey, '-')) { dwRet = pgeProductKeyBadLen; } else if (NULL == lpstrSku) { dwRet = pgeSkuNull; } else if (sizeof(pdpid->szSku) <= lstrlenA(lpstrSku)) { dwRet = pgeSkuBadLen; } else if (NULL == lpstrPid2) { dwRet = pgePid2Null; } else if (NULL == pdpid) { dwRet = pgeDigPidNull; } else if (pdpid->dwLength < sizeof(DIGITALPID)) { dwRet = pgeDigPidBadLen; } else if (!fOem && NULL == lpstrRpc) { dwRet = pgeMpcNull; } else if (NULL != lpstrRpc && 5 != lstrlenA(lpstrRpc)) { dwRet = pgeMpcBadLen; } else if (NULL != lpstrOemId && 0 != lstrlenA(lpstrOemId) && 4 != lstrlenA(lpstrOemId)) { dwRet = pgeOemIdBadLen; } else if (NULL != lpstrLocal24 && 0 != lstrlenA(lpstrLocal24) && 24 != lstrlenA(lpstrLocal24)) { dwRet = pgeLocalBad; } else { DWORD dwBinData = INVALID_PID; BOOL fExcluded = FALSE; int iBink = fOem ? 2 : 1; HRSRC hrsrcBink = NULL; HGLOBAL hresBink = NULL; LPBINKEY lpbink = NULL; if (NULL != lpbPublicKey) { dwBinData = DecodeProdKey( lpstrSecureCdKey, lpbPublicKey, dwcbPublicKey, lpstrLocal24, abBinCdKey, sizeof(abBinCdKey)); } else { // use default public keys lpbink = (LPBINKEY)-1; for ( iBink = fOem ? 2 : 1; INVALID_PID == dwBinData && NULL != lpbink; iBink +=2) { lpbink = NULL; hresBink = NULL; hrsrcBink = FindResource(g_hinst, MAKEINTRESOURCE(iBink), TEXT("BINK")); if (NULL != hrsrcBink) { hresBink = LoadResource(g_hinst, hrsrcBink); } if (NULL != hresBink) { lpbink = (LPBINKEY)LockResource(hresBink); if (NULL != lpbink) { dwKeyIdx = lpbink->dwKeyIdx; lpbPublicKey = lpbink->abPublicKey; dwcbPublicKey = *(LPDWORD)lpbPublicKey; dwBinData = DecodeProdKey( lpstrSecureCdKey, lpbPublicKey, dwcbPublicKey, // byte count of lpbPublicKey lpstrLocal24, abBinCdKey, sizeof(abBinCdKey)); UnlockResource(hresBink); } FreeResource(hresBink); } } } if (INVALID_PID == dwBinData) { dwRet = pgeProductKeyInvalid; } else { BOOL fCCP = (0 != (dwBinData & 1)); DWORD dwSeq = dwBinData / 2; // warning: byte order dependent DWORD_PTR dwSeq1; DWORD dwSeq2; char szRand[5+1]; if (NULL != pfCCP) { *pfCCP = fCCP; } if (NULL != lpdwSeq) { *lpdwSeq = dwSeq; } if (NULL != pfPSS) { // Note: this range is different that what shipped // with Win98, it's shifted by one. The old range // was (100000 < dwSeq && dwSeq <= 1000000) *pfPSS = (100000 <= dwSeq && dwSeq < 1000000); } ZeroMemory( pdpid, sizeof(*pdpid) ); pdpid->dwLength = sizeof(*pdpid); // version 3.0 pdpid->wVersionMajor = 3; pdpid->wVersionMinor = 0; // v-jhark 02-04-97 This is how other software (acme setup and // Darwin (msi)) generates random digits for the PID. It's not // the best random number because there may be some clustering // of values, but for our purposes this is acceptable. pdpid->dwRandom = GetTickCount(); DWORD dwYear; // last two digits of year DWORD dwJday; // day of the year 1 - 366 #if defined(WIN32) || defined(_WIN32) { SYSTEMTIME st = {0}; DWORDLONG dwlTime = 0; GetLocalTime(&st); SystemTimeToFileTime(&st, (LPFILETIME )&dwlTime); pdpid->dwTime = FileTimeToTimet((LPFILETIME)&dwlTime); if (st.wYear < 1998) { dwYear = 98; dwJday = 1; } else { dwYear = st.wYear % 100; dwJday = GetJulianDate(&st); } } #else { time_t lTime = time(NULL); pdpid->dwTime = (DWORD) lTime; struct tm tmNow = {0}; struct tm *ptmNow = localtime(&lTime); if (NULL != ptmNow) { tmNow = *ptmNow; } if (tmNow.tm_year < 98) { dwYear = 98; dwJday = 1; } else { dwYear = tmNow.tm_year % 100; dwJday = tmNow.tm_yday + 1; } } #endif // defined(WIN32) || defined(_WIN32) if (fOem) { fExcluded = IsSeqExcluded(dwSeq); if (fExcluded) { dwRet = pgeProductKeyExcluded; } else { pdpid->dwlt = ltOEM; dwSeq1 = dwSeq / 100000; dwSeq2 = dwSeq % 100000; dwSeq1 = AddCheckDigit((DWORD)dwSeq1); if (NULL == lpstrRpc) { wsprintfA( lpstrPid2, "%05.5ld-OEM-%07.7ld-%05.5ld", (LONG)(dwJday * 100 + dwYear % 100), (LONG)dwSeq1, (LONG)dwSeq2); } else { wsprintfA( lpstrPid2, "%s-OEM-%07.7ld-%05.5ld", lpstrRpc, (LONG)dwSeq1, (LONG)dwSeq2); } } // if (fExcluded) } // if (OEM) else { pdpid->dwlt = (fCCP) ? ltCCP : ltFPP; HRSRC hrsrcEscl = NULL; HGLOBAL hresEscl = NULL; // Excluded Site Code List LPDWORD pdwEscl; dwSeq1 = dwSeq / 1000000; dwSeq2 = dwSeq % 1000000; // check for excluded site codes // ESCL is Excluded Site Code List fExcluded = IsSeqExcluded(dwSeq); if (fExcluded) { dwRet = pgeProductKeyExcluded; } else { // check for special site codes // v-jhark 12-10-98 // // The PID group (v-jhark reports to manishac reports to richb) // has a reserved block of 10 Site Codes, 980 to 989, which has // been assigned as follows: // // 980 - Special IE 'all random', randomizes site code // 981 - Random for Trial Programs // 982 - Random, reserved for future use as of 12-10-98 // 983 - Random, reserved for future use as of 12-10-98 // 984 - IE ICP (Internet Content Provider)? 12-10-98 // 985 - reserved for future use as of 12-10-98 // 986 - reserved for future use as of 12-10-98 // 987 - reserved for future use as of 12-10-98 // 988 - reserved for future use as of 12-10-98 // 989 - reserved for future use as of 12-10-98 // // History: // 04-12-99 Revoked: 981 - Random for SBS (Small Business Server) // // if (270 == dwSeq1 || // Select 335 == dwSeq1 || // MSDN 981 == dwSeq1 || // Trial Programs 04-12-99 982 == dwSeq1 || // reserved for future use as of 07-09-98 983 == dwSeq1 || // reserved for future use as of 07-09-98 980 == dwSeq1 || // IE's "all random" (including site code) 460000000 == dwSeq) // special beta code only for this site and seq { // randomize dwSeq2 dwSeq2 = 0x7fffffff & pdpid->dwTime; dwSeq2 %= 1000000; // we only want the last six digits if (270 == dwSeq1) { pdpid->dwlt = ltSelect; } else if (335 == dwSeq1) { pdpid->dwlt = ltMSDN; } else if (980 == dwSeq1) { // Randomize even the PID 2.0's site code // (this is used free downloads like IE, etc.) // each row of the following table contains: // range start - first site included in range // range end - last site included in range // sum - place holder for calculated running // total of number of site codes // including current line // // there must be at least one valid site code in the table // or the randomization is skipped static short aasSiteRanges[][3] = { // These first three groups are reserved for mfg. // // { 5, 194, 0}, // {200, 235, 0}, // {241, 251, 0}, {255, 268, 0}, {271, 286, 0}, {311, 317, 0}, {320, 320, 0}, {325, 325, 0}, {339, 359, 0}, {361, 364, 0}, {396, 412, 0}, {414, 424, 0}, {426, 428, 0}, {430, 435, 0}, {437, 441, 0}, {443, 443, 0}, {445, 446, 0}, {448, 459, 0}, {461, 468, 0}, {510, 521, 0}, {543, 545, 0}, {550, 550, 0}, {574, 576, 0}, {578, 586, 0}, {589, 589, 0}, {805, 853, 0}, {948, 953, 0} }; #if TESTING_CODE FILE *pfLog; pfLog = fopen("TEST.LOG", "w"); for (int iSR = 0; iSR < ARRAY_SIZE(aasSiteRanges); ++iSR) { for ( int iSite = aasSiteRanges[iSR][0]; iSite <= aasSiteRanges[iSR][1]; ++iSite) { fprintf(pfLog, "%.3d\n", (int)iSite); } } fprintf(pfLog,"\n"); for (int iTest = 0; iTest < 50000; ++iTest) { #endif // randomize site code DWORD_PTR dwSeq1Rand = 0; #if defined(WIN32) || defined(_WIN32) LARGE_INTEGER liCount; if (QueryPerformanceCounter(&liCount)) { dwSeq1Rand = liCount.LowPart; } else { // QueryPerformanceCounter failed for some reason // use GlobalMemoryStatus as a backup random source MEMORYSTATUS mst = {sizeof(mst)}; GlobalMemoryStatus(&mst); // all we want is a random number dwSeq1Rand = mst.dwMemoryLoad ^ // percent of memory in use mst.dwTotalPhys ^ // bytes of physical memory mst.dwAvailPhys ^ // free physical memory bytes mst.dwTotalPageFile ^ // bytes of paging file mst.dwAvailPageFile ^ // free bytes of paging file mst.dwTotalVirtual ^ // user bytes of address space mst.dwAvailVirtual; // free user bytes } #else // all we want is a random number // first get the VolumeSerialNumber #pragma pack(1) // Media ID typedef struct { WORD wInfoLevel; DWORD dwSerialNum; char achVolLabel[11]; BYTE abFileSysType[8]; } MID, *PMID, FAR* LPMID; #pragma pack() LPMID pmid; union _REGS regs; struct _SREGS segregs; DWORD dwMem; dwMem = GlobalDosAlloc(sizeof(MID)); WORD wMidSelector = LOWORD(dwMem); WORD wMidSegment = HIWORD(dwMem); pmid = (LPMID)MAKELP(wMidSelector, 0); memset(pmid, 0, sizeof(MID)); ////GetMediaID(3, wMidSelector); memset(®s, 0, sizeof(regs)); memset(&segregs, 0, sizeof(segregs)); regs.x.ax = 0x440d; // DOS Function 440Dh - IOCTL for Block Device regs.h.cl = 0x66; // Minor Code 66h - Get Media ID regs.h.ch = 0x08; // Device category (must be 08h) regs.x.bx = 3; // Drive C: regs.x.dx = 0; // pmid offset segregs.ds = wMidSelector; // wMidSegment; segregs.es = wMidSelector; // wMidSegment; _intdosx(®s, ®s, &segregs); BOOL fInfoSuccess = !regs.x.cflag; DWORD dwVolumeSerialNumber = pmid->dwSerialNum; GlobalDosFree(wMidSelector); // now get the drive parameters UINT uNumberHeads; UINT uNumberTracks; UINT uSectorsPerTrack; memset(®s, 0, sizeof(regs)); memset(&segregs, 0, sizeof(segregs)); regs.h.ah = 0x08; // BIOS Function 08h - Get drive parameters regs.x.dx = 2; // 0 = A:, 1 = B:, 2 = C: _int86x( 0x13, // BIOS Disk ®s, ®s, &segregs); BOOL fOk = (!regs.x.cflag); if (fOk) { uNumberHeads = regs.h.dh + 1; uNumberTracks = ((regs.h.cl & 0xC0) << 2) + regs.h.ch + 1; uSectorsPerTrack = regs.h.cl & 0x3F; } // build up our random number from chaotic data dwSeq1Rand = GetTickCount() ^ // mSec system has been running dwVolumeSerialNumber ^ // Volume Serial Number uNumberHeads ^ // number of heads uNumberTracks ^ // number of tracks uSectorsPerTrack; // Sectors per Track #endif // defined(WIN32) || defined(_WIN32) int i; short sTotal = 0; // Calculate the running total column for (i = 0; i < ARRAY_SIZE(aasSiteRanges); ++i) { sTotal += 1 + aasSiteRanges[i][1] - aasSiteRanges[i][0]; aasSiteRanges[i][2] = sTotal; } // pick a random number within the table if (0 < sTotal) // skip this if the table's empty { dwSeq1Rand %= sTotal; // look up actual site code short sTotalPrev = 0; for (i = 0; aasSiteRanges[i][2] <= (short)dwSeq1Rand; ++i) { sTotalPrev = aasSiteRanges[i][2]; } dwSeq1 = aasSiteRanges[i][0] + dwSeq1Rand - sTotalPrev; #if TESTING_CODE fprintf(pfLog, "%.3d, %.3d\n", (int) dwSeq1Rand, (int)dwSeq1); } fclose(pfLog); #endif } } } dwSeq2 = AddCheckDigit(dwSeq2); wsprintfA( szRand, "%02.2ld%03.3ld", (LONG)(((dwKeyIdx/2)%100)), (LONG)((pdpid->dwRandom/10)%1000L) ); wsprintfA( lpstrPid2, "%s-%03.3ld-%07.7ld-%s", lpstrRpc, (LONG)dwSeq1, (LONG)dwSeq2, szRand); } } if (pgeSuccess == dwRet) { lstrcpyA(pdpid->szPid2, lpstrPid2); pdpid->dwKeyIdx = dwKeyIdx; CopyMemory(pdpid->abCdKey, abBinCdKey, sizeof(pdpid->abCdKey)); lstrcpyA(pdpid->szSku, lpstrSku); if (NULL != lpstrOemId) { lstrcpyA(pdpid->szOemId, lpstrOemId); } #if defined(WIN32) || defined(_WIN32) CHardware hwid; lstrcpyA(pdpid->aszHardwareIdStatic, hwid.GetID()); pdpid->dwBiosChecksumStatic = hwid.GetBiosCrc32(); pdpid->dwVolSerStatic = hwid.GetVolSer(); pdpid->dwTotalRamStatic = hwid.GetTotalRamMegs(); pdpid->dwVideoBiosChecksumStatic = hwid.GetVideoBiosCrc32(); #endif // defined(WIN32) || defined(_WIN32) pdpid->dwCrc32 = CRC_32((LPBYTE)pdpid, sizeof(*pdpid)-sizeof(pdpid->dwCrc32)); #if defined BUILD_PRO || defined BUILD_VOL || defined BUILD_EVAL if( !CheckSkuRange(fOem, dwSeq)) { dwRet = pgeProductKeyExcluded; } #endif } } } return dwRet; } extern "C" BOOL STDAPICALLTYPE PIDGenA( LPSTR lpstrSecureCdKey, // [IN] 25-character Secure CD-Key (gets U-Cased) LPCSTR lpstrRpc, // [IN] 5-character Release Product Code LPCSTR lpstrSku, // [IN] Stock Keeping Unit (formatted like 123-12345) LPCSTR lpstrOemId, // [IN] 4-character OEM ID or NULL LPSTR lpstrLocal24, // [IN] 24-character ordered set to use for decode base conversion or NULL for default set (gets U-Cased) LPBYTE lpbPublicKey, // [IN] pointer to optional public key or NULL DWORD dwcbPublicKey, // [IN] byte length of optional public key DWORD dwKeyIdx, // [IN] key pair index optional public key BOOL fOem, // [IN] is this an OEM install? LPSTR lpstrPid2, // [OUT] PID 2.0, pass in ptr to 24 character array LPBYTE lpbPid3, // [OUT] pointer to binary PID3 buffer. First DWORD is the length LPDWORD lpdwSeq, // [OUT] optional ptr to sequence number (can be NULL) LPBOOL pfCCP, // [OUT] optional ptr to Compliance Checking flag (can be NULL) LPBOOL pfPSS) // [OUT] optional ptr to 'PSS Assigned' flag (can be NULL) { DWORD dwRet; dwRet = PIDGenRc( lpstrSecureCdKey, lpstrRpc, lpstrSku, lpstrOemId, lpstrLocal24, lpbPublicKey, dwcbPublicKey, dwKeyIdx, fOem, lpstrPid2, lpbPid3, lpdwSeq, pfCCP, pfPSS); // pfPSS, 'PSS Assigned' flag return pgeSuccess == dwRet; } // Simplified interface to PidGen extern "C" DWORD STDAPICALLTYPE PIDGenSimpA( LPSTR lpstrSecureCdKey, // [IN] 25-character Secure CD-Key (gets U-Cased) LPCSTR lpstrRpc, // [IN] 5-character Release Product Code LPCSTR lpstrSku, // [IN] Stock Keeping Unit (formatted like 123-12345) LPCSTR lpstrOemId, // [IN] 4-character OEM ID or NULL BOOL fOem, // [IN] is this an OEM install? LPSTR lpstrPid2, // [OUT] PID 2.0, pass in ptr to 24 character array LPBYTE lpbPid3, // [OUT] pointer to binary PID3 buffer. First DWORD is the length LPDWORD lpdwSeq, // [OUT] optional ptr to sequence number (can be NULL) LPBOOL pfCCP) // [OUT] optional ptr to Compliance Checking flag (can be NULL) { DWORD dwRet; dwRet = PIDGenRc( lpstrSecureCdKey, lpstrRpc, lpstrSku, lpstrOemId, NULL, // lpstrLocal24, ordered set to use for decode base NULL, // lpbPublicKey, optional public key 0, // dwcbPublicKey, byte length of optional public key 0, // dwKeyIdx, key pair index optional public key fOem, lpstrPid2, lpbPid3, lpdwSeq, pfCCP, NULL); // pfPSS, 'PSS Assigned' flag return dwRet; } #if defined(WIN32) || defined(_WIN32) // ISSUE:vijeshs:08/15/2000 move all error checks into PidGenRc extern "C" BOOL STDAPICALLTYPE PIDGenW( LPWSTR lpstrSecureCdKey, // [IN] 25-character Secure CD-Key (gets U-Cased) LPCWSTR lpstrRpc, // [IN] 5-character Release Product Code LPCWSTR lpstrSku, // [IN] Stock Keeping Unit (formatted like 123-12345) LPCWSTR lpstrOemId, // [IN] 4-character OEM ID or NULL LPWSTR lpstrLocal24, // [IN] 24-character ordered set to use for decode base conversion or NULL for default set (gets U-Cased) LPBYTE lpbPublicKey, // [IN] pointer to optional public key or NULL DWORD dwcbPublicKey, // [IN] byte length of optional public key DWORD dwKeyIdx, // [IN] key pair index optional public key BOOL fOem, // [IN] is this an OEM install? LPWSTR lpstrPid2, // [OUT] PID 2.0, pass in ptr to 24 character array LPBYTE lpbPid3, // [OUT] pointer to DigitalPID. First DWORD is the length LPDWORD lpdwSeq, // [OUT] optional ptr to sequence number (can be NULL) LPBOOL pfCCP, // [OUT] optional ptr to Compliance Checking flag (can be NULL) LPBOOL pfPSS) // [OUT] optional ptr to 'PSS Assigned' flag (can be NULL) { char SecureCdKey[25+4+1]; char RpcCode[5+1]; char Sku[32]; char OemId[4+1]; char Local24[24+1]; char Pid20Buffer[24+1]; BOOL rc; BOOL used = FALSE; // ISSUE:vijeshs:08/15/2000 enforce sizes if (!Pid20Buffer || !lpstrSecureCdKey || (!fOem && !lpstrRpc) || !lpstrSku) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (!WideCharToMultiByte(CP_ACP,0,lpstrSecureCdKey,-1,SecureCdKey,sizeof(SecureCdKey),"z",&used) || used) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (NULL != lpstrRpc) { if (!WideCharToMultiByte(CP_ACP,0,lpstrRpc,-1,RpcCode,sizeof(RpcCode),"z",&used) || used) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } } if (!WideCharToMultiByte(CP_ACP,0,lpstrSku,-1,Sku,sizeof(Sku),"z",&used) || used) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (lpstrOemId) { if (!WideCharToMultiByte(CP_ACP,0,lpstrOemId,-1,OemId,sizeof(OemId),"z",&used) || used) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } } if (lpstrLocal24) { if (!WideCharToMultiByte(CP_ACP,0,lpstrLocal24,-1,Local24,sizeof(Local24),"z",&used) || used) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } } rc = PIDGenA( SecureCdKey, (NULL == lpstrRpc) ? NULL : RpcCode, Sku, lpstrOemId ? OemId : NULL, lpstrLocal24 ? Local24 : NULL, lpbPublicKey, dwcbPublicKey, dwKeyIdx, fOem, Pid20Buffer, lpbPid3, lpdwSeq, pfCCP, pfPSS); if (!rc) { *Pid20Buffer = (WCHAR)0; } else if (!MultiByteToWideChar( CP_ACP,0,Pid20Buffer,-1,lpstrPid2,25 )) { return FALSE; } return rc; } // Simplified interface to PidGen extern "C" DWORD STDAPICALLTYPE PIDGenSimpW( LPWSTR lpstrSecureCdKey, // [IN] 25-character Secure CD-Key (gets U-Cased) LPCWSTR lpstrRpc, // [IN] 5-character Release Product Code LPCWSTR lpstrSku, // [IN] Stock Keeping Unit (formatted like 123-12345) LPCWSTR lpstrOemId, // [IN] 4-character OEM ID or NULL BOOL fOem, // [IN] is this an OEM install? LPWSTR lpstrPid2, // [OUT] PID 2.0, pass in ptr to 24 character array LPBYTE lpbPid3, // [OUT] pointer to binary PID3 buffer. First DWORD is the length LPDWORD lpdwSeq, // [OUT] optional ptr to sequence number (can be NULL) LPBOOL pfCCP) // [OUT] optional ptr to Compliance Checking flag (can be NULL) { DWORD dwRet; dwRet = PIDGenW( lpstrSecureCdKey, lpstrRpc, lpstrSku, lpstrOemId, NULL, // lpstrLocal24, ordered set to use for decode base NULL, // lpbPublicKey, optional public key 0, // dwcbPublicKey, byte length of optional public key 0, // dwKeyIdx, key pair index optional public key fOem, lpstrPid2, lpbPid3, lpdwSeq, pfCCP, NULL); // pfPSS, 'PSS Assigned' flag return dwRet; } #endif // defined(WIN32) || defined(_WIN32)