"Fossies" - the Fresh Open Source Software Archive

Member "src/ExpandVolume/ExpandVolume.c" (10 Oct 2018, 26723 Bytes) of package /windows/misc/VeraCrypt_1.23-Hotfix-2_Source.zip:


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 "ExpandVolume.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.22_Source_vs_1.23_Source.

    1 /*
    2  Legal Notice: Some portions of the source code contained in this file were
    3  derived from the source code of TrueCrypt 7.1a, which is
    4  Copyright (c) 2003-2012 TrueCrypt Developers Association and which is
    5  governed by the TrueCrypt License 3.0, also from the source code of
    6  Encryption for the Masses 2.02a, which is Copyright (c) 1998-2000 Paul Le Roux
    7  and which is governed by the 'License Agreement for Encryption for the Masses'
    8  and also from the source code of extcv, which is Copyright (c) 2009-2010 Kih-Oskh
    9  or Copyright (c) 2012-2013 Josef Schneider <josef@netpage.dk>
   10 
   11  Modifications and additions to the original source code (contained in this file)
   12  and all other portions of this file are Copyright (c) 2013-2017 IDRIX
   13  and are governed by the Apache License 2.0 the full text of which is
   14  contained in the file License.txt included in VeraCrypt binary and source
   15  code distribution packages. */
   16 
   17 #include "Tcdefs.h"
   18 
   19 #include <time.h>
   20 #include <math.h>
   21 #include <dbt.h>
   22 #include <fcntl.h>
   23 #include <io.h>
   24 #include <sys/stat.h>
   25 #include <windowsx.h>
   26 #include <stdio.h>
   27 
   28 #include "Apidrvr.h"
   29 #include "Volumes.h"
   30 #include "Crypto.h"
   31 #include "Dlgcode.h"
   32 #include "Language.h"
   33 #include "Pkcs5.h"
   34 #include "Random.h"
   35 #include "Progress.h"
   36 
   37 #include "InitDataArea.h"
   38 #include "ExpandVolume.h"
   39 #include "Resource.h"
   40 
   41 #ifndef SRC_POS
   42 #define SRC_POS (__FUNCTION__ ":" TC_TO_STRING(__LINE__))
   43 #endif
   44 
   45 #define DEBUG_EXPAND_VOLUME
   46 
   47 #ifdef DEBUG_EXPAND_VOLUME
   48 #define DebugAddProgressDlgStatus  AddProgressDlgStatus
   49 #else
   50 #define DebugAddProgressDlgStatus(a,b)
   51 #endif
   52 
   53 
   54 HWND hCurPage;      /* Handle to window with progress bar (used by FormatNoFs)*/
   55 int nPbar;          /* Control ID of progress bar (used by FormatNoFs) */
   56 volatile BOOL bVolTransformThreadCancel = FALSE; /* TRUE if the user cancels/pauses volume expansion */
   57 
   58 // internal functions
   59 static int UpdateVolumeHeaderHostSize (wchar_t *lpszVolume, Password *pVolumePassword, HWND hwndDlg, uint64 newHostSize, uint64 *pDataSize, BOOL initFreeSpace);
   60 static int FsctlExtendVolume(wchar_t * szVolume, LONGLONG nTotalSectors );
   61 
   62 
   63 /*
   64     MountVolTemp
   65 
   66     Mounts a trucrypt volume temporarily (using any free drive number)
   67 
   68     Parameters:
   69 
   70         hwndDlg : HWND
   71             [in] handle to parent window
   72 
   73         volumePath : char *
   74             [in] Pointer to a string that contains the volume path
   75 
   76         driveNo : int *
   77             [out] returns the drive number (0='A',...)
   78 
   79         password : Password *
   80             [in] Pointer to the volume password
   81 
   82     Return value:
   83 
   84         int with Truecrypt error code (ERR_SUCCESS on success)
   85 
   86 */
   87 int MountVolTemp (HWND hwndDlg, wchar_t *volumePath, int *driveNo, Password *password, int pkcs5, int pim)
   88 {
   89     MountOptions mountOptions;
   90     ZeroMemory (&mountOptions, sizeof (mountOptions));
   91 
   92     *driveNo = GetLastAvailableDrive ();
   93 
   94     if (*driveNo == -1)
   95     {
   96         *driveNo = -2;
   97         return ERR_NO_FREE_DRIVES;
   98     }
   99 
  100     mountOptions.ReadOnly = FALSE;
  101     mountOptions.Removable = ConfigReadInt ("MountVolumesRemovable", FALSE);
  102     mountOptions.ProtectHiddenVolume = FALSE;
  103     mountOptions.PreserveTimestamp = bPreserveTimestamp;
  104     mountOptions.PartitionInInactiveSysEncScope = FALSE;
  105     mountOptions.UseBackupHeader = FALSE;
  106 
  107     if (MountVolume (hwndDlg, *driveNo, volumePath, password, pkcs5, pim, FALSE, FALSE, FALSE, TRUE, &mountOptions, FALSE, FALSE) < 1)
  108     {
  109         *driveNo = -3;
  110         return ERR_VOL_MOUNT_FAILED;
  111     }
  112     return 0;
  113 }
  114 
  115 
  116 /*
  117     FsctlExtendVolume
  118 
  119     Expands a volume by sending the FSCTL_EXTEND_VOLUME ioctl command to the volume
  120 
  121     Parameters:
  122 
  123         szVolume : char *
  124             [in] Pointer to a string that contains the volume GUID
  125 
  126         nTotalSectors : LONGLONG
  127             [in] specifies the total size of the volume, in sectors
  128 
  129     Return value:
  130 
  131         int with Truecrypt error code (ERR_SUCCESS on success)
  132 
  133     Remarks: only supported by NTFS and RAW file systems
  134 
  135 */
  136 static int FsctlExtendVolume(wchar_t * szVolume, LONGLONG nTotalSectors )
  137 {
  138     HANDLE hDevice;   // handle to the volume to be extended
  139     BOOL bResult;     // results flag
  140     DWORD nbytes;     // discard results
  141     DWORD dwError;
  142     int nStatus = ERR_OS_ERROR;
  143 
  144     hDevice = CreateFile(szVolume,
  145                     GENERIC_READ,
  146                     FILE_SHARE_READ |
  147                     FILE_SHARE_WRITE,
  148                     NULL,
  149                     OPEN_EXISTING,
  150                     FILE_ATTRIBUTE_NORMAL,
  151                     NULL);
  152 
  153     if (hDevice == INVALID_HANDLE_VALUE)
  154         goto error;
  155 
  156     bResult = DeviceIoControl(hDevice,
  157                             FSCTL_EXTEND_VOLUME,
  158                             &nTotalSectors, sizeof(nTotalSectors),
  159                             NULL, 0,
  160                             &nbytes,
  161                             (LPOVERLAPPED) NULL);
  162 
  163     if (bResult)
  164         nStatus = ERR_SUCCESS;
  165 
  166 error:
  167 
  168     dwError = GetLastError ();
  169 
  170     if (hDevice != INVALID_HANDLE_VALUE)
  171         CloseHandle (hDevice);
  172 
  173     SetLastError (dwError);
  174 
  175     return nStatus;
  176 }
  177 
  178 
  179 BOOL GetFileSystemType(const wchar_t *szFileName, enum EV_FileSystem *pFS)
  180 {
  181     wchar_t szFS[256];
  182     wchar_t root[MAX_PATH];
  183 
  184     *pFS = EV_FS_TYPE_RAW;
  185 
  186     if (!GetVolumePathName (szFileName, root, ARRAYSIZE (root)))
  187         return FALSE;
  188 
  189     if ( GetVolumeInformation (root, NULL, 0, NULL, NULL, NULL, szFS, ARRAYSIZE(szFS)) )
  190     {
  191         if (!wcsncmp (szFS, L"NTFS", 4))
  192             *pFS = EV_FS_TYPE_NTFS;
  193         else if (!wcsncmp (szFS, L"FAT", 3)) // FAT16, FAT32
  194             *pFS = EV_FS_TYPE_FAT;
  195         else if (!_wcsnicmp (szFS, L"exFAT", 5)) // exFAT
  196             *pFS = EV_FS_TYPE_EXFAT;
  197         else
  198             *pFS = EV_FS_TYPE_RAW;
  199     }
  200     else
  201     {
  202         return FALSE;
  203     }
  204 
  205     return TRUE;
  206 }
  207 
  208 /*
  209     QueryVolumeInfo
  210 
  211     Retrieves the free disk space and file size limit on the truecrypt volume host
  212 
  213     Parameters:
  214 
  215         hwndDlg : HWND
  216             [in] handle to parent window
  217 
  218         lpszVolume : char *
  219             [in] Pointer to a string that contains the volume path
  220 
  221         pHostSizeFree : uint64 *
  222             [out] returns the free space available on the host (always zero for devices)
  223 
  224         pSizeLimitFS : uint64 *
  225             [out] returns the file size limit of the host file system
  226 
  227     Return value:
  228 
  229         int with TrueCrypt error code (ERR_SUCCESS on success)
  230 
  231 */
  232 int QueryVolumeInfo (HWND hwndDlg, const wchar_t *lpszVolume, uint64 * pHostSizeFree, uint64 * pSizeLimitFS )
  233 {
  234     int nStatus = ERR_OS_ERROR;
  235     wchar_t szDiskFile[TC_MAX_PATH], root[MAX_PATH];
  236     BOOL bDevice;
  237     enum EV_FileSystem fs;
  238 
  239     *pSizeLimitFS = (uint64)-1;
  240 
  241     CreateFullVolumePath (szDiskFile, sizeof(szDiskFile), lpszVolume, &bDevice);
  242 
  243     if (bDevice)
  244     {
  245         *pHostSizeFree=0;
  246         return ERR_SUCCESS;
  247     }
  248 
  249     if (!GetVolumePathName (szDiskFile, root, ARRAYSIZE (root)))
  250     {
  251         nStatus = ERR_OS_ERROR;
  252         goto error;
  253     }
  254 
  255     if( ! GetDiskFreeSpaceEx (root,(PULARGE_INTEGER)pHostSizeFree,NULL,NULL) )
  256     {
  257         nStatus = ERR_OS_ERROR;
  258         goto error;
  259     }
  260 
  261     if ( ! GetFileSystemType(root,&fs) )
  262     {
  263         nStatus = ERR_OS_ERROR;
  264         goto error;
  265     }
  266 
  267     /*  file size limits
  268         FAT16 / FAT32 : 4 GB minus 1 byte (2^32 bytes minus 1 byte)
  269         exFAT: 128 PiB − 1 byte
  270         NTFS :  Architecturally : 16 exabytes minus 1 KB (26^4 bytes minus 1 KB)
  271                 Implementation (Windows Server 2008): 16 terabytes minus 64 KB (2^44 bytes minus 64 KB)
  272     */
  273     switch (fs)
  274     {
  275     case EV_FS_TYPE_NTFS:
  276         *pSizeLimitFS = 16 * BYTES_PER_TB - 64 * BYTES_PER_KB;
  277         break;
  278     case EV_FS_TYPE_EXFAT:
  279         *pSizeLimitFS = 128 * BYTES_PER_PB - 1;
  280         break;
  281     case EV_FS_TYPE_FAT:
  282         *pSizeLimitFS = 4 * BYTES_PER_GB - 1;
  283         break;
  284     default:
  285         *pSizeLimitFS = (uint64)-1;
  286     }
  287 
  288     nStatus = ERR_SUCCESS;
  289 
  290 error:
  291 
  292     return nStatus;
  293 }
  294 
  295 BOOL GetNtfsNumberOfSectors(wchar_t * rootPath, uint64 * pNumberOfSectors, DWORD *pBytesPerSector)
  296 {
  297     HANDLE hDevice;
  298     BOOL bResult;
  299     DWORD nbytes, dwError;
  300     size_t len;
  301     NTFS_VOLUME_DATA_BUFFER ntfsvdb;
  302     wchar_t szVolumeGUID[128];
  303 
  304     // get volume name
  305     if (!GetVolumeNameForVolumeMountPoint(rootPath,szVolumeGUID,ARRAYSIZE(szVolumeGUID)))
  306     {
  307         return FALSE;
  308     }
  309 
  310     // strip trailing backslash from volume GUID (otherwise it means root dir)
  311     len = wcslen(szVolumeGUID);
  312     if (len>0)
  313         --len;
  314     if (szVolumeGUID[len]==L'\\')
  315         szVolumeGUID[len]=0;
  316 
  317     hDevice = CreateFile(szVolumeGUID,
  318                     GENERIC_READ,
  319                     FILE_SHARE_READ | FILE_SHARE_WRITE,
  320                     NULL,
  321                     OPEN_EXISTING,
  322                     FILE_ATTRIBUTE_NORMAL,
  323                     NULL);
  324 
  325     if (hDevice == INVALID_HANDLE_VALUE)
  326         return (FALSE);
  327 
  328     bResult = DeviceIoControl(hDevice,
  329                             FSCTL_GET_NTFS_VOLUME_DATA,
  330                              NULL, 0,
  331                             &ntfsvdb, sizeof(ntfsvdb),
  332                             &nbytes,
  333                             (LPOVERLAPPED) NULL);
  334 
  335     if (bResult)
  336     {
  337         if (pNumberOfSectors)
  338             *pNumberOfSectors = ntfsvdb.NumberSectors.QuadPart;
  339         if (pBytesPerSector)
  340             *pBytesPerSector = ntfsvdb.BytesPerSector;
  341     }
  342 
  343     dwError = GetLastError ();
  344     CloseHandle(hDevice);
  345     SetLastError (dwError);
  346 
  347     return (bResult);
  348 }
  349 
  350 
  351 uint64 GetVolumeDataAreaSize (uint64 volumeSize, BOOL legacyVolume)
  352 {
  353     uint64 reservedSize;
  354 
  355     if (legacyVolume)
  356         reservedSize = TC_VOLUME_HEADER_SIZE_LEGACY;
  357     else
  358         reservedSize = TC_TOTAL_VOLUME_HEADERS_SIZE;
  359 
  360     if (volumeSize < reservedSize)
  361         return 0;
  362 
  363     return volumeSize - reservedSize;
  364 }
  365 
  366 
  367 uint64 GetVolumeSizeByDataAreaSize (uint64 dataAreaSize, BOOL legacyVolume)
  368 {
  369     uint64 reservedSize;
  370 
  371     if (legacyVolume)
  372         reservedSize = TC_VOLUME_HEADER_SIZE_LEGACY;
  373     else
  374         reservedSize = TC_TOTAL_VOLUME_HEADERS_SIZE;
  375 
  376     return dataAreaSize + reservedSize;
  377 }
  378 
  379 
  380 int ExtendFileSystem (HWND hwndDlg , wchar_t *lpszVolume, Password *pVolumePassword, int VolumePkcs5, int VolumePim, uint64 newDataAreaSize)
  381 {
  382     wchar_t szVolumeGUID[128];
  383     int driveNo = -1;
  384     wchar_t rootPath[] = L"A:\\";
  385     enum EV_FileSystem fs;
  386     DWORD dwError;
  387     int nStatus = ERR_SUCCESS;
  388     DWORD BytesPerSector;
  389 
  390     // mount and resize file system
  391 
  392     DebugAddProgressDlgStatus (hwndDlg, L"Mounting volume ...\r\n");
  393 
  394     nStatus=MountVolTemp(hwndDlg, lpszVolume, &driveNo, pVolumePassword, VolumePkcs5, VolumePim);
  395     if (nStatus!=ERR_SUCCESS)
  396     {
  397         driveNo = -1;
  398         goto error;
  399     }
  400 
  401     rootPath[0] += driveNo;
  402 
  403     if ( !GetFileSystemType(rootPath,&fs) )
  404     {
  405         dwError = GetLastError();
  406         if (dwError == ERROR_UNRECOGNIZED_VOLUME)
  407         {
  408             // raw volume with unrecognized file system -> return with no error
  409             nStatus = ERR_SUCCESS;
  410             goto error;
  411         }
  412         nStatus = ERR_OS_ERROR;
  413         goto error;
  414     }
  415 
  416     if (fs != EV_FS_TYPE_RAW && fs != EV_FS_TYPE_NTFS )
  417     {
  418         // FsctlExtendVolume only supports NTFS and RAW -> return with no error
  419         nStatus = ERR_SUCCESS;
  420         goto error;
  421     }
  422 
  423     // Get volume GUID
  424     if (!GetVolumeNameForVolumeMountPoint(rootPath,szVolumeGUID,ARRAYSIZE(szVolumeGUID)))
  425     {
  426         nStatus = ERR_OS_ERROR;
  427         goto error;
  428     }
  429     else
  430     {
  431         // strip trailing backslash from volume GUID (otherwise it means root dir)
  432         size_t len = wcslen(szVolumeGUID);
  433         if (len>0) --len;
  434         if (szVolumeGUID[len]==L'\\') szVolumeGUID[len]=0;
  435     }
  436 
  437     // Get Sector Size
  438     if ( !GetNtfsNumberOfSectors(rootPath, NULL, &BytesPerSector) )
  439     {
  440         nStatus = ERR_OS_ERROR;
  441         goto error;
  442     }
  443 
  444     DebugAddProgressDlgStatus (hwndDlg, L"Extending file system ...\r\n");
  445 
  446     // extend volume
  447     nStatus = FsctlExtendVolume(szVolumeGUID, newDataAreaSize/BytesPerSector );
  448 
  449 error:
  450 
  451     dwError = GetLastError();
  452 
  453     if (driveNo>=0)
  454     {
  455         DebugAddProgressDlgStatus (hwndDlg, L"Unmounting volume ...\r\n");
  456         UnmountVolume (hwndDlg, driveNo, TRUE);
  457     }
  458 
  459     SetLastError (dwError);
  460 
  461     return nStatus;
  462 }
  463 
  464 /*
  465     ExpandVolume
  466 
  467     Sets the volume size in the volume header (and backup header) to a larger value,
  468     and resizes the filesystem within the volume (only NTFS supported)
  469 
  470     Parameters:
  471 
  472         hwndDlg : HWND
  473             [in] handle to progress dialog
  474 
  475         lpszVolume : char *
  476             [in] Pointer to a string that contains the path to the truecrypt volume
  477 
  478         pVolumePassword : Password *
  479             [in] Pointer to the volume password
  480 
  481         newHostSize : uint64
  482             [in] new value of the volume host size (can be zero for devices,
  483                  which means the volume should use all space of the host device)
  484 
  485         initFreeSpace : BOOL
  486             [in] if true, the new volume space will be initalized with random data
  487 
  488     Return value:
  489 
  490         int with Truecrypt error code (ERR_SUCCESS on success)
  491 
  492     Remarks: a lot of code is from TrueCrypt 'Common\Password.c' :: ChangePwd()
  493 
  494 */
  495 static int ExpandVolume (HWND hwndDlg, wchar_t *lpszVolume, Password *pVolumePassword, int VolumePkcs5, int VolumePim, uint64 newHostSize, BOOL initFreeSpace)
  496 {
  497     int nDosLinkCreated = 1, nStatus = ERR_OS_ERROR;
  498     wchar_t szDiskFile[TC_MAX_PATH], szCFDevice[TC_MAX_PATH];
  499     wchar_t szDosDevice[TC_MAX_PATH];
  500     char buffer[TC_VOLUME_HEADER_EFFECTIVE_SIZE];
  501     PCRYPTO_INFO cryptoInfo = NULL, ci = NULL;
  502     void *dev = INVALID_HANDLE_VALUE;
  503     DWORD dwError;
  504     BOOL bDevice;
  505     uint64 hostSize=0, newDataAreaSize, currentVolSize;
  506     DWORD HostSectorSize;
  507     FILETIME ftCreationTime;
  508     FILETIME ftLastWriteTime;
  509     FILETIME ftLastAccessTime;
  510     BOOL bTimeStampValid = FALSE;
  511     LARGE_INTEGER headerOffset;
  512     BOOL backupHeader;
  513     byte *wipeBuffer = NULL;
  514     uint32 workChunkSize = TC_VOLUME_HEADER_GROUP_SIZE;
  515 
  516     if (pVolumePassword->Length == 0) return -1;
  517 
  518     WaitCursor ();
  519 
  520     CreateFullVolumePath (szDiskFile, sizeof(szDiskFile), lpszVolume, &bDevice);
  521 
  522     if (bDevice == FALSE)
  523     {
  524         wcscpy (szCFDevice, szDiskFile);
  525     }
  526     else
  527     {
  528         nDosLinkCreated = FakeDosNameForDevice (szDiskFile, szDosDevice, sizeof(szDosDevice), szCFDevice, sizeof(szCFDevice), FALSE);
  529 
  530         if (nDosLinkCreated != 0) // note: nStatus == ERR_OS_ERROR
  531             goto error;
  532     }
  533 
  534     dev = CreateFile (szCFDevice, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  535 
  536     if (dev == INVALID_HANDLE_VALUE)
  537         goto error;
  538 
  539     if (bDevice)
  540     {
  541         /* This is necessary to determine the hidden volume header offset */
  542 
  543         if (dev == INVALID_HANDLE_VALUE)
  544         {
  545             goto error;
  546         }
  547         else
  548         {
  549             PARTITION_INFORMATION diskInfo;
  550             DWORD dwResult;
  551             BOOL bResult;
  552 
  553             bResult = GetPartitionInfo (lpszVolume, &diskInfo);
  554 
  555             if (bResult)
  556             {
  557                 hostSize = diskInfo.PartitionLength.QuadPart;
  558                 HostSectorSize = TC_SECTOR_SIZE_FILE_HOSTED_VOLUME; //TO DO: get the real host disk sector size
  559             }
  560             else
  561             {
  562                 BYTE dgBuffer[256];
  563 
  564                 bResult = DeviceIoControl (dev, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0,
  565                     dgBuffer, sizeof (dgBuffer), &dwResult, NULL);
  566 
  567                 if (!bResult)
  568                 {
  569                     DISK_GEOMETRY geo;
  570                     if (DeviceIoControl (dev, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, (LPVOID) &geo, sizeof (geo), &dwResult, NULL))
  571                     {
  572                         hostSize = geo.Cylinders.QuadPart * geo.SectorsPerTrack * geo.TracksPerCylinder * geo.BytesPerSector;
  573                         HostSectorSize = geo.BytesPerSector;
  574 
  575                         if (CurrentOSMajor >= 6)
  576                         {
  577                             STORAGE_READ_CAPACITY storage = {0};
  578 
  579                             storage.Version = sizeof (STORAGE_READ_CAPACITY);
  580                             storage.Size = sizeof (STORAGE_READ_CAPACITY);
  581                             if (DeviceIoControl (dev, IOCTL_STORAGE_READ_CAPACITY, NULL, 0, (LPVOID) &storage, sizeof (storage), &dwResult, NULL)
  582                                 && (dwResult >= sizeof (storage))
  583                                 && (storage.Size == sizeof (STORAGE_READ_CAPACITY))
  584                                 )
  585                             {
  586                                 hostSize = storage.DiskLength.QuadPart;
  587                             }
  588                         }
  589                     }
  590                     else
  591                     {
  592                         goto error;
  593                     }
  594                 }
  595                 else
  596                 {
  597                     hostSize = ((PDISK_GEOMETRY_EX) dgBuffer)->DiskSize.QuadPart;
  598                     HostSectorSize = ((PDISK_GEOMETRY_EX) dgBuffer)->Geometry.BytesPerSector;
  599                 }
  600             }
  601 
  602             if (hostSize == 0)
  603             {
  604                 nStatus = ERR_VOL_SIZE_WRONG;
  605                 goto error;
  606             }
  607         }
  608     }
  609     else
  610     {
  611         LARGE_INTEGER fileSize;
  612         if (!GetFileSizeEx (dev, &fileSize))
  613         {
  614             nStatus = ERR_OS_ERROR;
  615             goto error;
  616         }
  617 
  618         hostSize = fileSize.QuadPart;
  619         HostSectorSize = TC_SECTOR_SIZE_FILE_HOSTED_VOLUME; //TO DO: get the real host disk sector size
  620     }
  621 
  622     if (Randinit ())
  623     {
  624         if (CryptoAPILastError == ERROR_SUCCESS)
  625             nStatus = ERR_RAND_INIT_FAILED;
  626         else
  627             nStatus = ERR_CAPI_INIT_FAILED;
  628         goto error;
  629     }
  630 
  631     if (!bDevice && bPreserveTimestamp)
  632     {
  633         /* Remember the container modification/creation date and time, (used to reset file date and time of
  634         file-hosted volumes after password change (or attempt to), in order to preserve plausible deniability
  635         of hidden volumes (last password change time is stored in the volume header). */
  636 
  637         if (GetFileTime ((HANDLE) dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime) == 0)
  638         {
  639             bTimeStampValid = FALSE;
  640             MessageBoxW (hwndDlg, GetString ("GETFILETIME_FAILED_PW"), lpszTitle, MB_OK | MB_ICONEXCLAMATION);
  641         }
  642         else
  643             bTimeStampValid = TRUE;
  644     }
  645 
  646     // Seek the volume header
  647     headerOffset.QuadPart = TC_VOLUME_HEADER_OFFSET;
  648 
  649     if (!SetFilePointerEx ((HANDLE) dev, headerOffset, NULL, FILE_BEGIN))
  650     {
  651         nStatus = ERR_OS_ERROR;
  652         goto error;
  653     }
  654 
  655     /* Read in volume header */
  656     nStatus = _lread ((HFILE) dev, buffer, sizeof (buffer));
  657     if (nStatus != sizeof (buffer))
  658     {
  659         // Windows may report EOF when reading sectors from the last cluster of a device formatted as NTFS
  660         memset (buffer, 0, sizeof (buffer));
  661     }
  662 
  663     /* Try to decrypt the header */
  664 
  665     nStatus = ReadVolumeHeader (FALSE, buffer, pVolumePassword, VolumePkcs5, VolumePim, FALSE, &cryptoInfo, NULL);
  666     if (nStatus == ERR_CIPHER_INIT_WEAK_KEY)
  667         nStatus = 0;    // We can ignore this error here
  668 
  669     if (nStatus != 0)
  670     {
  671         cryptoInfo = NULL;
  672         goto error;
  673     }
  674 
  675     if (cryptoInfo->HeaderFlags & TC_HEADER_FLAG_ENCRYPTED_SYSTEM)
  676     {
  677         nStatus = ERR_SYS_HIDVOL_HEAD_REENC_MODE_WRONG;
  678         goto error;
  679     }
  680 
  681     if (bDevice && newHostSize == 0)
  682     {
  683         // this means we shall take all host space as new volume size
  684         newHostSize = hostSize;
  685     }
  686 
  687     if ( newHostSize % cryptoInfo->SectorSize != 0  || newHostSize > TC_MAX_VOLUME_SIZE || (bDevice && newHostSize > hostSize) )
  688     {
  689         // 1. must be multiple of sector size
  690         // 2. truecrypt volume size limit
  691         // 3. for devices volume size can't be larger than host size
  692         cryptoInfo = NULL;
  693         nStatus = ERR_PARAMETER_INCORRECT;
  694         goto error;
  695     }
  696 
  697     newDataAreaSize = GetVolumeDataAreaSize (newHostSize, cryptoInfo->LegacyVolume);
  698 
  699     if (cryptoInfo->LegacyVolume)
  700     {
  701         if (bDevice)
  702         {
  703             if (initFreeSpace)
  704             {
  705                 // unsupported
  706                 cryptoInfo = NULL;
  707                 nStatus = ERR_PARAMETER_INCORRECT;
  708                 goto error;
  709             }
  710             else
  711             {
  712                 // note: dummy value (only used for parameter checks)
  713                 cryptoInfo->VolumeSize.Value = newDataAreaSize - TC_MINVAL_FS_EXPAND;
  714             }
  715         }
  716         else
  717         {
  718             cryptoInfo->VolumeSize.Value = GetVolumeDataAreaSize (hostSize, TRUE);
  719         }
  720     }
  721 
  722     currentVolSize = GetVolumeSizeByDataAreaSize (cryptoInfo->VolumeSize.Value, cryptoInfo->LegacyVolume);
  723 
  724     if ( newDataAreaSize < cryptoInfo->VolumeSize.Value + TC_MINVAL_FS_EXPAND )
  725     {
  726         // shrinking a volume or enlarging by less then TC_MINVAL_FS_EXPAND is not allowed
  727         cryptoInfo = NULL;
  728         nStatus = ERR_PARAMETER_INCORRECT;
  729         goto error;
  730     }
  731 
  732     InitProgressBar ( newHostSize, currentVolSize, FALSE, FALSE, FALSE, TRUE);
  733 
  734     if (bVolTransformThreadCancel)
  735     {
  736         SetLastError(0);
  737         nStatus = ERR_USER_ABORT;
  738         goto error;
  739     }
  740 
  741     if (!bDevice) {
  742         LARGE_INTEGER liNewSize;
  743 
  744         liNewSize.QuadPart=(LONGLONG)newHostSize;
  745 
  746         // Preallocate the file
  747         if (!SetFilePointerEx (dev, liNewSize, NULL, FILE_BEGIN)
  748             || !SetEndOfFile (dev)
  749             || SetFilePointer (dev, 0, NULL, FILE_BEGIN) != 0)
  750         {
  751             nStatus = ERR_OS_ERROR;
  752             goto error;
  753         }
  754     }
  755 
  756     if (initFreeSpace)
  757     {
  758         uint64 startSector;
  759         int64 num_sectors;
  760 
  761         // fill new space with random data
  762         startSector = currentVolSize/HostSectorSize ;
  763         num_sectors = (newHostSize/HostSectorSize) - startSector;
  764 
  765         if (bDevice && !StartFormatWriteThread())
  766         {
  767             nStatus = ERR_OS_ERROR;
  768             goto error;
  769         }
  770 
  771         DebugAddProgressDlgStatus(hwndDlg, L"Writing random data to new space ...\r\n");
  772 
  773         SetFormatSectorSize(HostSectorSize);
  774         nStatus = FormatNoFs (hwndDlg, startSector, num_sectors, dev, cryptoInfo, FALSE);
  775 
  776         dwError = GetLastError();
  777         StopFormatWriteThread();
  778         SetLastError (dwError);
  779     }
  780     else
  781     {
  782         UpdateProgressBar(newHostSize);
  783     }
  784 
  785     if (nStatus != ERR_SUCCESS)
  786     {
  787         dwError = GetLastError();
  788         DebugAddProgressDlgStatus(hwndDlg, L"Error: failed to write random data ...\r\n");
  789         if ( !bDevice ) {
  790             // restore original size of the container file
  791             LARGE_INTEGER liOldSize;
  792             liOldSize.QuadPart=(LONGLONG)hostSize;
  793             if (!SetFilePointerEx (dev, liOldSize, NULL, FILE_BEGIN) || !SetEndOfFile (dev))
  794             {
  795                 DebugAddProgressDlgStatus(hwndDlg, L"Warning: failed to restore original size of the container file\r\n");
  796             }
  797         }
  798         SetLastError (dwError);
  799         goto error;
  800     }
  801 
  802     RandSetHashFunction (cryptoInfo->pkcs5);
  803 
  804     // Re-encrypt the volume header forn non-legacy volumes: backup header first
  805     backupHeader = TRUE;
  806     headerOffset.QuadPart = TC_VOLUME_HEADER_OFFSET + newHostSize - TC_VOLUME_HEADER_GROUP_SIZE;
  807 
  808     /* note: updating the header is not neccessary for legay volumes */
  809     while ( !cryptoInfo->LegacyVolume )
  810     {
  811         if (backupHeader)
  812             DebugAddProgressDlgStatus(hwndDlg, L"Writing re-encrypted backup header ...\r\n");
  813         else
  814             DebugAddProgressDlgStatus(hwndDlg, L"Writing re-encrypted primary header ...\r\n");
  815 
  816         // Prepare new volume header
  817         nStatus = CreateVolumeHeaderInMemory (hwndDlg, FALSE,
  818             buffer,
  819             cryptoInfo->ea,
  820             cryptoInfo->mode,
  821             pVolumePassword,
  822             cryptoInfo->pkcs5,
  823             VolumePim,
  824             (char*)(cryptoInfo->master_keydata),
  825             &ci,
  826             newDataAreaSize,
  827             0, // hiddenVolumeSize
  828             cryptoInfo->EncryptedAreaStart.Value,
  829             newDataAreaSize,
  830             cryptoInfo->RequiredProgramVersion,
  831             cryptoInfo->HeaderFlags,
  832             cryptoInfo->SectorSize,
  833             FALSE ); // use slow poll
  834 
  835         if (ci != NULL)
  836             crypto_close (ci);
  837 
  838         if (nStatus != 0)
  839             goto error;
  840 
  841         if (!SetFilePointerEx ((HANDLE) dev, headerOffset, NULL, FILE_BEGIN))
  842         {
  843             nStatus = ERR_OS_ERROR;
  844             goto error;
  845         }
  846 
  847         if (!WriteEffectiveVolumeHeader (bDevice, dev, buffer))
  848         {
  849             nStatus = ERR_OS_ERROR;
  850             goto error;
  851         }
  852 
  853         if ( ( backupHeader && !initFreeSpace )
  854             || ( bDevice
  855                 && !cryptoInfo->LegacyVolume
  856                 && !cryptoInfo->hiddenVolume
  857                 && cryptoInfo->HeaderVersion == 4   // BUG in TrueCrypt: doing this only for v4 make no sense
  858                 && (cryptoInfo->HeaderFlags & TC_HEADER_FLAG_NONSYS_INPLACE_ENC) != 0
  859                 && (cryptoInfo->HeaderFlags & ~TC_HEADER_FLAG_NONSYS_INPLACE_ENC) == 0 )
  860             )
  861         {
  862             //DebugAddProgressDlgStatus(hwndDlg, L"WriteRandomDataToReservedHeaderAreas() ...\r\n");
  863             PCRYPTO_INFO dummyInfo = NULL;
  864             LARGE_INTEGER hiddenOffset;
  865 
  866             nStatus = WriteRandomDataToReservedHeaderAreas (hwndDlg, dev, cryptoInfo, newDataAreaSize, !backupHeader, backupHeader);
  867             if (nStatus != ERR_SUCCESS)
  868                 goto error;
  869 
  870             // write fake hidden volume header to protect against attacks that use statistical entropy
  871             // analysis to detect presence of hidden volumes
  872             hiddenOffset.QuadPart = headerOffset.QuadPart + TC_HIDDEN_VOLUME_HEADER_OFFSET;
  873 
  874             nStatus = CreateVolumeHeaderInMemory (hwndDlg, FALSE,
  875                 buffer,
  876                 cryptoInfo->ea,
  877                 cryptoInfo->mode,
  878                 NULL,
  879                 0,
  880                 0,
  881                 NULL,
  882                 &dummyInfo,
  883                 newDataAreaSize,
  884                 newDataAreaSize, // hiddenVolumeSize
  885                 cryptoInfo->EncryptedAreaStart.Value,
  886                 newDataAreaSize,
  887                 cryptoInfo->RequiredProgramVersion,
  888                 cryptoInfo->HeaderFlags,
  889                 cryptoInfo->SectorSize,
  890                 FALSE ); // use slow poll
  891 
  892             if (nStatus != ERR_SUCCESS)
  893                 goto error;
  894 
  895             crypto_close (dummyInfo);
  896 
  897             if (!SetFilePointerEx ((HANDLE) dev, hiddenOffset, NULL, FILE_BEGIN))
  898             {
  899                 nStatus = ERR_OS_ERROR;
  900                 goto error;
  901             }
  902 
  903             if (!WriteEffectiveVolumeHeader (bDevice, dev, buffer))
  904             {
  905                 nStatus = ERR_OS_ERROR;
  906                 goto error;
  907             }
  908         }
  909 
  910         FlushFileBuffers (dev);
  911 
  912         if (!backupHeader)
  913             break;
  914 
  915         backupHeader = FALSE;
  916         headerOffset.QuadPart = TC_VOLUME_HEADER_OFFSET; // offset for main header
  917     }
  918 
  919     /* header successfully updated */
  920     nStatus = ERR_SUCCESS;
  921 
  922     if (bVolTransformThreadCancel)
  923     {
  924         nStatus = ERR_USER_ABORT;
  925         goto error;
  926     }
  927 
  928     /* wipe old backup header */
  929     if ( !cryptoInfo->LegacyVolume )
  930     {
  931         byte wipeRandChars [TC_WIPE_RAND_CHAR_COUNT];
  932         byte wipeRandCharsUpdate [TC_WIPE_RAND_CHAR_COUNT];
  933         byte wipePass;
  934         UINT64_STRUCT unitNo;
  935         LARGE_INTEGER offset;
  936         WipeAlgorithmId wipeAlgorithm = TC_WIPE_35_GUTMANN;
  937 
  938         if (    !RandgetBytes (hwndDlg, wipeRandChars, TC_WIPE_RAND_CHAR_COUNT, TRUE)
  939             || !RandgetBytes (hwndDlg, wipeRandCharsUpdate, TC_WIPE_RAND_CHAR_COUNT, TRUE)
  940             )
  941         {
  942             nStatus = ERR_OS_ERROR;
  943             goto error;
  944         }
  945 
  946         DebugAddProgressDlgStatus(hwndDlg, L"Wiping old backup header ...\r\n");
  947 
  948         wipeBuffer = (byte *) TCalloc (workChunkSize);
  949         if (!wipeBuffer)
  950         {
  951             nStatus = ERR_OUTOFMEMORY;
  952             goto error;
  953         }
  954 
  955         offset.QuadPart = currentVolSize - TC_VOLUME_HEADER_GROUP_SIZE;
  956         unitNo.Value = offset.QuadPart;
  957 
  958         for (wipePass = 1; wipePass <= GetWipePassCount (wipeAlgorithm); ++wipePass)
  959         {
  960             if (!WipeBuffer (wipeAlgorithm, wipeRandChars, wipePass, wipeBuffer, workChunkSize))
  961             {
  962                 ULONG i;
  963                 for (i = 0; i < workChunkSize; ++i)
  964                 {
  965                     wipeBuffer[i] = wipePass;
  966                 }
  967 
  968                 EncryptDataUnits (wipeBuffer, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, cryptoInfo);
  969                 memcpy (wipeRandCharsUpdate, wipeBuffer, sizeof (wipeRandCharsUpdate));
  970             }
  971 
  972             if ( !SetFilePointerEx (dev, offset, NULL, FILE_BEGIN)
  973                 || _lwrite ((HFILE)dev, (LPCSTR)wipeBuffer, workChunkSize) == HFILE_ERROR
  974                 )
  975             {
  976                 // Write error
  977                 DebugAddProgressDlgStatus(hwndDlg, L"Warning: Failed to wipe old backup header\r\n");
  978                 MessageBoxW (hwndDlg, L"WARNING: Failed to wipe old backup header!\n\nIt may be possible to use the current volume password to decrypt the old backup header even after a future password change.\n", lpszTitle, MB_OK | MB_ICONEXCLAMATION);
  979                 if (wipePass == 1)
  980                     continue; // retry once
  981                 // non-critical error - it's better to continue
  982                 nStatus = ERR_SUCCESS;
  983                 goto error;
  984             }
  985             FlushFileBuffers(dev);
  986             // we don't check FlushFileBuffers() return code, because it fails for devices
  987             // (same implementation in password.c - a bug or not ???)
  988         }
  989 
  990         burn (wipeRandChars, TC_WIPE_RAND_CHAR_COUNT);
  991         burn (wipeRandCharsUpdate, TC_WIPE_RAND_CHAR_COUNT);
  992     }
  993 
  994 error:
  995     dwError = GetLastError ();
  996 
  997     if (wipeBuffer)
  998     {
  999         burn (wipeBuffer, workChunkSize);
 1000         TCfree (wipeBuffer);
 1001         wipeBuffer = NULL;
 1002     }
 1003 
 1004     burn (buffer, sizeof (buffer));
 1005 
 1006     if (cryptoInfo != NULL)
 1007         crypto_close (cryptoInfo);
 1008 
 1009     if (bTimeStampValid)
 1010     {
 1011         // Restore the container timestamp (to preserve plausible deniability of possible hidden volume).
 1012         if (SetFileTime (dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime) == 0)
 1013             MessageBoxW (hwndDlg, GetString ("SETFILETIME_FAILED_PW"), lpszTitle, MB_OK | MB_ICONEXCLAMATION);
 1014     }
 1015 
 1016     if (dev != INVALID_HANDLE_VALUE)
 1017         CloseHandle ((HANDLE) dev);
 1018 
 1019     if (nDosLinkCreated == 0)
 1020         RemoveFakeDosName (szDiskFile, szDosDevice);
 1021 
 1022     RandStop (FALSE);
 1023 
 1024     if (bVolTransformThreadCancel)
 1025         nStatus = ERR_USER_ABORT;
 1026 
 1027     SetLastError (dwError);
 1028 
 1029     if (nStatus == ERR_SUCCESS)
 1030     {
 1031         nStatus = ExtendFileSystem (hwndDlg, lpszVolume, pVolumePassword, VolumePkcs5, VolumePim, newDataAreaSize);
 1032     }
 1033 
 1034     return nStatus;
 1035 }
 1036 
 1037 
 1038 
 1039 void __cdecl volTransformThreadFunction (void *pExpandDlgParam)
 1040 {
 1041     int nStatus;
 1042     EXPAND_VOL_THREAD_PARAMS *pParam=(EXPAND_VOL_THREAD_PARAMS *)pExpandDlgParam;
 1043     HWND hwndDlg = (HWND) pParam->hwndDlg;
 1044 
 1045     nStatus = ExpandVolume (hwndDlg, (wchar_t*)pParam->szVolumeName, pParam->pVolumePassword,
 1046         pParam->VolumePkcs5, pParam->VolumePim, pParam->newSize, pParam->bInitFreeSpace );
 1047 
 1048     if (nStatus!=ERR_SUCCESS && nStatus!=ERR_USER_ABORT)
 1049             handleError (hwndDlg, nStatus, SRC_POS);
 1050 
 1051     bVolTransformThreadCancel = FALSE;
 1052 
 1053     PostMessage (hwndDlg, TC_APPMSG_VOL_TRANSFORM_THREAD_ENDED, 0, nStatus);
 1054 
 1055     _endthread ();
 1056 }