Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

133 lines
4.0 KiB

  1. #include "stdafx.h"
  2. #include "password.h"
  3. // password categories
  4. enum {STRONG_PWD_UPPER=0,STRONG_PWD_LOWER,STRONG_PWD_NUM,STRONG_PWD_PUNC};
  5. #define STRONG_PWD_CATS (STRONG_PWD_PUNC + 1)
  6. #define NUM_LETTERS 26
  7. #define NUM_NUMBERS 10
  8. #define MIN_PWD_LEN 8
  9. // password must contain at least one each of:
  10. // uppercase, lowercase, punctuation and numbers
  11. DWORD CreateGoodPassword(BYTE *szPwd, DWORD dwLen)
  12. {
  13. if (dwLen-1 < MIN_PWD_LEN)
  14. {
  15. return ERROR_PASSWORD_RESTRICTION;
  16. }
  17. HCRYPTPROV hProv;
  18. DWORD dwErr = 0;
  19. if (CryptAcquireContext(&hProv,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT) == FALSE)
  20. {
  21. return GetLastError();
  22. }
  23. // zero it out and decrement the size to allow for trailing '\0'
  24. ZeroMemory(szPwd,dwLen);
  25. dwLen--;
  26. // generate a pwd pattern, each byte is in the range
  27. // (0..255) mod STRONG_PWD_CATS
  28. // this indicates which character pool to take a char from
  29. BYTE *pPwdPattern = new BYTE[dwLen];
  30. BOOL fFound[STRONG_PWD_CATS];
  31. do
  32. {
  33. // bug!bug! does CGR() ever fail?
  34. CryptGenRandom(hProv,dwLen,pPwdPattern);
  35. fFound[STRONG_PWD_UPPER] =
  36. fFound[STRONG_PWD_LOWER] =
  37. fFound[STRONG_PWD_PUNC] =
  38. fFound[STRONG_PWD_NUM] = FALSE;
  39. for (DWORD i=0; i < dwLen; i++)
  40. {
  41. fFound[pPwdPattern[i] % STRONG_PWD_CATS] = TRUE;
  42. }
  43. // check that each character category is in the pattern
  44. } while (!fFound[STRONG_PWD_UPPER] || !fFound[STRONG_PWD_LOWER] || !fFound[STRONG_PWD_PUNC] || !fFound[STRONG_PWD_NUM]);
  45. // populate password with random data
  46. // this, in conjunction with pPwdPattern, is
  47. // used to determine the actual data
  48. CryptGenRandom(hProv,dwLen,szPwd);
  49. for (DWORD i=0; i < dwLen; i++)
  50. {
  51. BYTE bChar = 0;
  52. // there is a bias in each character pool because of the % function
  53. switch (pPwdPattern[i] % STRONG_PWD_CATS)
  54. {
  55. case STRONG_PWD_UPPER : bChar = 'A' + szPwd[i] % NUM_LETTERS;
  56. break;
  57. case STRONG_PWD_LOWER : bChar = 'a' + szPwd[i] % NUM_LETTERS;
  58. break;
  59. case STRONG_PWD_NUM : bChar = '0' + szPwd[i] % NUM_NUMBERS;
  60. break;
  61. case STRONG_PWD_PUNC :
  62. default:
  63. char *szPunc="!@#$%^&*()_-+=[{]};:\'\"<>,./?\\|~`";
  64. DWORD dwLenPunc = lstrlenA(szPunc);
  65. bChar = szPunc[szPwd[i] % dwLenPunc];
  66. break;
  67. }
  68. szPwd[i] = bChar;
  69. }
  70. delete pPwdPattern;
  71. if (hProv != NULL)
  72. {
  73. CryptReleaseContext(hProv,0);
  74. }
  75. return dwErr;
  76. }
  77. // Creates a secure password
  78. // caller must GlobalFree Return pointer
  79. // iSize = size of password to create
  80. LPTSTR CreatePassword(int iSize)
  81. {
  82. LPTSTR pszPassword = NULL;
  83. BYTE *szPwd = new BYTE[iSize];
  84. DWORD dwPwdLen = iSize;
  85. int i = 0;
  86. // use the new secure password generator
  87. // unfortunately this baby doesn't use unicode.
  88. // so we'll call it and then convert it to unicode afterwards.
  89. if (0 == CreateGoodPassword(szPwd,dwPwdLen))
  90. {
  91. #if defined(UNICODE) || defined(_UNICODE)
  92. // convert it to unicode and copy it back into our unicode buffer.
  93. // compute the length
  94. i = MultiByteToWideChar(CP_ACP, 0, (LPSTR) szPwd, -1, NULL, 0);
  95. if (i <= 0)
  96. {goto CreatePassword_Exit;}
  97. pszPassword = (LPTSTR) GlobalAlloc(GPTR, i * sizeof(TCHAR));
  98. if (!pszPassword)
  99. {goto CreatePassword_Exit;}
  100. i = MultiByteToWideChar(CP_ACP, 0, (LPSTR) szPwd, -1, pszPassword, i);
  101. if (i <= 0)
  102. {
  103. GlobalFree(pszPassword);
  104. pszPassword = NULL;
  105. goto CreatePassword_Exit;
  106. }
  107. // make sure ends with null
  108. pszPassword[i - 1] = 0;
  109. #else
  110. pszPassword = (LPSTR) GlobalAlloc(GPTR, _tcslen((LPTSTR) szPwd) * sizeof(TCHAR));
  111. #endif
  112. }
  113. CreatePassword_Exit:
  114. if (szPwd){delete szPwd;szPwd=NULL;}
  115. return pszPassword;
  116. }