secpassword.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. #include "rar.hpp"
  2. /* // OPENMPT ADDITION
  3. #if defined(_WIN_ALL)
  4. typedef BOOL (WINAPI *CRYPTPROTECTMEMORY)(LPVOID pData,DWORD cbData,DWORD dwFlags);
  5. typedef BOOL (WINAPI *CRYPTUNPROTECTMEMORY)(LPVOID pData,DWORD cbData,DWORD dwFlags);
  6. #ifndef CRYPTPROTECTMEMORY_BLOCK_SIZE
  7. #define CRYPTPROTECTMEMORY_BLOCK_SIZE 16
  8. #define CRYPTPROTECTMEMORY_SAME_PROCESS 0x00
  9. #define CRYPTPROTECTMEMORY_CROSS_PROCESS 0x01
  10. #endif
  11. class CryptLoader
  12. {
  13. private:
  14. HMODULE hCrypt;
  15. bool LoadCalled;
  16. public:
  17. CryptLoader()
  18. {
  19. hCrypt=NULL;
  20. pCryptProtectMemory=NULL;
  21. pCryptUnprotectMemory=NULL;
  22. LoadCalled=false;
  23. }
  24. ~CryptLoader()
  25. {
  26. if (hCrypt!=NULL)
  27. FreeLibrary(hCrypt);
  28. hCrypt=NULL;
  29. pCryptProtectMemory=NULL;
  30. pCryptUnprotectMemory=NULL;
  31. };
  32. void Load()
  33. {
  34. if (!LoadCalled)
  35. {
  36. hCrypt = LoadSysLibrary(L"Crypt32.dll");
  37. if (hCrypt != NULL)
  38. {
  39. // Available since Vista.
  40. pCryptProtectMemory = (CRYPTPROTECTMEMORY)GetProcAddress(hCrypt, "CryptProtectMemory");
  41. pCryptUnprotectMemory = (CRYPTUNPROTECTMEMORY)GetProcAddress(hCrypt, "CryptUnprotectMemory");
  42. }
  43. LoadCalled=true;
  44. }
  45. }
  46. CRYPTPROTECTMEMORY pCryptProtectMemory;
  47. CRYPTUNPROTECTMEMORY pCryptUnprotectMemory;
  48. };
  49. // We need to call FreeLibrary when RAR is exiting.
  50. static CryptLoader GlobalCryptLoader;
  51. #endif
  52. */ // OPENMPT ADDITION
  53. SecPassword::SecPassword()
  54. {
  55. return; // OPENMPT ADDITION
  56. CrossProcess=false;
  57. Set(L"");
  58. }
  59. SecPassword::~SecPassword()
  60. {
  61. return; // OPENMPT ADDITION
  62. Clean();
  63. }
  64. void SecPassword::Clean()
  65. {
  66. return; // OPENMPT ADDITION
  67. PasswordSet=false;
  68. cleandata(Password,sizeof(Password));
  69. }
  70. // When we call memset in end of function to clean local variables
  71. // for security reason, compiler optimizer can remove such call.
  72. // So we use our own function for this purpose.
  73. void cleandata(void *data,size_t size)
  74. {
  75. return; // OPENMPT ADDITION
  76. if (data==NULL || size==0)
  77. return;
  78. #if defined(_WIN_ALL) && defined(_MSC_VER)
  79. SecureZeroMemory(data,size);
  80. #else
  81. // 'volatile' is required. Otherwise optimizers can remove this function
  82. // if cleaning local variables, which are not used after that.
  83. volatile byte *d = (volatile byte *)data;
  84. for (size_t i=0;i<size;i++)
  85. d[i]=0;
  86. #endif
  87. }
  88. // We got a complain from user that it is possible to create WinRAR dump
  89. // with "Create dump file" command in Windows Task Manager and then easily
  90. // locate Unicode password string in the dump. It is unsecure if several
  91. // people share the same computer and somebody left WinRAR copy with entered
  92. // password. So we decided to obfuscate the password to make it more difficult
  93. // to find it in dump.
  94. void SecPassword::Process(const wchar *Src,size_t SrcSize,wchar *Dst,size_t DstSize,bool Encode)
  95. {
  96. return; // OPENMPT ADDITION
  97. // Source string can be shorter than destination as in case when we process
  98. // -p<pwd> parameter, so we need to take into account both sizes.
  99. memcpy(Dst,Src,Min(SrcSize,DstSize)*sizeof(*Dst));
  100. SecHideData(Dst,DstSize*sizeof(*Dst),Encode,CrossProcess);
  101. }
  102. void SecPassword::Get(wchar *Psw,size_t MaxSize)
  103. {
  104. return; // OPENMPT ADDITION
  105. if (PasswordSet)
  106. {
  107. Process(Password,ASIZE(Password),Psw,MaxSize,false);
  108. Psw[MaxSize-1]=0;
  109. }
  110. else
  111. *Psw=0;
  112. }
  113. void SecPassword::Set(const wchar *Psw)
  114. {
  115. return; // OPENMPT ADDITION
  116. if (*Psw==0)
  117. {
  118. PasswordSet=false;
  119. memset(Password,0,sizeof(Password));
  120. }
  121. else
  122. {
  123. PasswordSet=true;
  124. Process(Psw,wcslen(Psw)+1,Password,ASIZE(Password),true);
  125. }
  126. }
  127. size_t SecPassword::Length()
  128. {
  129. return 0; // OPENMPT ADDITION
  130. wchar Plain[MAXPASSWORD];
  131. Get(Plain,ASIZE(Plain));
  132. size_t Length=wcslen(Plain);
  133. cleandata(Plain,ASIZE(Plain));
  134. return Length;
  135. }
  136. bool SecPassword::operator == (SecPassword &psw)
  137. {
  138. return false; // OPENMPT ADDITION
  139. // We cannot compare encoded data directly, because there is no guarantee
  140. // than encryption function will always produce the same result for same
  141. // data (salt?) and because we do not clean the rest of password buffer
  142. // after trailing zero before encoding password. So we decode first.
  143. wchar Plain1[MAXPASSWORD],Plain2[MAXPASSWORD];
  144. Get(Plain1,ASIZE(Plain1));
  145. psw.Get(Plain2,ASIZE(Plain2));
  146. bool Result=wcscmp(Plain1,Plain2)==0;
  147. cleandata(Plain1,ASIZE(Plain1));
  148. cleandata(Plain2,ASIZE(Plain2));
  149. return Result;
  150. }
  151. void SecHideData(void *Data,size_t DataSize,bool Encode,bool CrossProcess)
  152. {
  153. /* // OPENMPT ADDITION
  154. // CryptProtectMemory is not available in UWP and CryptProtectData
  155. // increases data size not allowing in place conversion.
  156. #if defined(_WIN_ALL)
  157. // Try to utilize the secure Crypt[Un]ProtectMemory if possible.
  158. if (GlobalCryptLoader.pCryptProtectMemory==NULL)
  159. GlobalCryptLoader.Load();
  160. size_t Aligned=DataSize-DataSize%CRYPTPROTECTMEMORY_BLOCK_SIZE;
  161. DWORD Flags=CrossProcess ? CRYPTPROTECTMEMORY_CROSS_PROCESS : CRYPTPROTECTMEMORY_SAME_PROCESS;
  162. if (Encode)
  163. {
  164. if (GlobalCryptLoader.pCryptProtectMemory!=NULL)
  165. {
  166. if (!GlobalCryptLoader.pCryptProtectMemory(Data,DWORD(Aligned),Flags))
  167. {
  168. ErrHandler.GeneralErrMsg(L"CryptProtectMemory failed");
  169. ErrHandler.SysErrMsg();
  170. ErrHandler.Exit(RARX_FATAL);
  171. }
  172. return;
  173. }
  174. }
  175. else
  176. {
  177. if (GlobalCryptLoader.pCryptUnprotectMemory!=NULL)
  178. {
  179. if (!GlobalCryptLoader.pCryptUnprotectMemory(Data,DWORD(Aligned),Flags))
  180. {
  181. ErrHandler.GeneralErrMsg(L"CryptUnprotectMemory failed");
  182. ErrHandler.SysErrMsg();
  183. ErrHandler.Exit(RARX_FATAL);
  184. }
  185. return;
  186. }
  187. }
  188. #endif
  189. // CryptProtectMemory is not available, so only slightly obfuscate data.
  190. uint Key;
  191. #ifdef _WIN_ALL
  192. Key=GetCurrentProcessId();
  193. #elif defined(_UNIX)
  194. Key=getpid();
  195. #else
  196. Key=0; // Just an arbitrary value.
  197. #endif
  198. for (size_t I=0;I<DataSize;I++)
  199. *((byte *)Data+I)^=Key+I+75;
  200. */ // OPENMPT ADDITION
  201. }