unrarsrc  6.1.7
About: unrar extracts, views and tests the contents of archives created with the RAR archiver.
  Fossies Dox: unrarsrc-6.1.7.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

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