1 // Berkeley Open Infrastructure for Network Computing
2 // http://boinc.berkeley.edu
3 //
4 // Source Code Originally from:
5 // http://support.microsoft.com/kb/814463
6 //
7 
8 #include "stdafx.h"
9 #include "password.h"
10 
11 //Generates a Random string of length nLen - 1.  Buffer ppwd must allocate an extra character for null terminator.
12 //Returns TRUE if successful, FALSE if fails.
13 //Extended error information can be obtained from GetLastError().
GenPwd(TCHAR * ppwd,int nLen)14 BOOL GenPwd(TCHAR* ppwd, int nLen)
15 {
16 	BOOL bResult = FALSE;	//assume failure
17 	HCRYPTPROV hProv = NULL;
18 	HCRYPTHASH hHash = NULL;
19 
20 	//Storage for random string 4 times longer than the resulting password.
21 	DWORD dwBufSize = nLen*4;
22 	DWORD dwSize = Base64EncodeGetRequiredLength((int)dwBufSize);
23 	LPSTR pEncodedString = NULL;
24 	LPBYTE pRandomBuf = NULL;
25 	TCHAR* pTRandomPwd = NULL;
26 
27 	try
28 	{
29 		pEncodedString = new char[dwSize];
30 		pRandomBuf = new BYTE[dwBufSize];
31 
32 		// Try to acquire context to Crypto provider.
33 		if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_SILENT))
34 		{
35 			if (GetLastError() == NTE_BAD_KEYSET) //Test for non-existent keyset
36 			{
37 				if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_SILENT | CRYPT_NEWKEYSET))
38 					throw(GetLastError());
39 			}
40 			else
41 				throw(GetLastError());
42 		}
43 
44 		//Generate a random sequence.
45 		if (!CryptGenRandom(hProv, dwBufSize, pRandomBuf))
46 		{
47 			throw(GetLastError());
48 		}
49 
50 		//Get a handle to a hash, then hash the random stream.
51 		if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
52 		{
53 			throw(GetLastError());
54 		}
55 
56 		if (!CryptHashData(hHash, pRandomBuf, dwBufSize, NULL))
57 		{
58 			throw(GetLastError());
59 		}
60 
61 		//Destroy the hash object.
62 		CryptDestroyHash(hHash);
63 		//Release Provider context
64 		CryptReleaseContext(hProv, 0);
65 
66 		//Encode the hash value to base64.
67 		if (!Base64Encode(pRandomBuf, dwBufSize, pEncodedString, (int*) &dwSize, 0))
68 		{
69 			throw(GetLastError());
70 		}
71 
72 		//Determine how many tchars you need to convert string to base64.
73 		int nTchars = (int) strlen(pEncodedString);
74 
75 		pTRandomPwd = new TCHAR[nTchars];
76 
77 #ifdef UNICODE
78 		if (MultiByteToWideChar(CP_UTF8, 0, pEncodedString, nTchars, pTRandomPwd, nTchars) == 0)
79 		{
80 			throw(GetLastError());
81 		}
82 #else
83 		_tcsncpy( pTRandomPwd, pEncodedString, nLen);
84 #endif
85 
86 		//Copy the first x characters of random string to output buffer.
87 		_tcsncpy(ppwd, pTRandomPwd, nLen);
88 		//Add null terminator to ppwd string.
89 		ppwd[nLen] = _T('\0');
90 
91 		bResult = TRUE;
92 
93 	}
94 	catch (DWORD)
95 	{
96 		//Set return value to false.
97 		bResult = FALSE;
98 	}
99 	catch (...)
100 	{
101 		//Unknown error, throw.
102 		throw;
103 	}
104 
105 	//Clean up memory.
106 	if (pRandomBuf)
107 	{
108 		delete[] pRandomBuf;
109 		pRandomBuf = NULL;
110 	}
111 
112 	if (pEncodedString)
113 	{
114 		delete[] pEncodedString;
115 		pEncodedString = NULL;
116 	}
117 
118 	if (pTRandomPwd)
119 	{
120 		delete[] pTRandomPwd;
121 		pTRandomPwd = NULL;
122 	}
123 
124 	return bResult;
125 }
126 
127 
GenerateRandomPassword(tstring & strPassword,DWORD dwDesiredLength)128 BOOL GenerateRandomPassword( tstring& strPassword, DWORD dwDesiredLength )
129 {
130     TCHAR szBuffer[512];
131     BOOL  bReturnValue = FALSE;
132 
133     bReturnValue = GenPwd(szBuffer, dwDesiredLength);
134 
135     strPassword = szBuffer;
136 
137     return bReturnValue;
138 }
139 
140