"Fossies" - the Fresh Open Source Software Archive

Member "unrar/secpassword.cpp" (4 May 2022, 5642 Bytes) of package /linux/misc/unrarsrc-6.1.7.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "secpassword.cpp" see the Fossies "Dox" file reference documentation.

    1 #include "rar.hpp"
    2 
    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 
    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 
   13 class 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.
   54 static CryptLoader GlobalCryptLoader;
   55 #endif
   56 
   57 SecPassword::SecPassword()
   58 {
   59   CrossProcess=false;
   60   Set(L"");
   61 }
   62 
   63 
   64 SecPassword::~SecPassword()
   65 {
   66   Clean();
   67 }
   68 
   69 
   70 void SecPassword::Clean()
   71 {
   72   PasswordSet=false;
   73   cleandata(Password,sizeof(Password));
   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.
   80 void 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.
  102 void 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 
  111 void 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 
  125 void 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 
  140 size_t SecPassword::Length()
  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 
  150 bool SecPassword::operator == (SecPassword &psw)
  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 
  166 void 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");
  183         ErrHandler.SysErrMsg();
  184         ErrHandler.Exit(RARX_FATAL);
  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");
  196         ErrHandler.SysErrMsg();
  197         ErrHandler.Exit(RARX_FATAL);
  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 }