예제 #1
0
파일: Format.c 프로젝트: cocoon/VeraCrypt
int FormatNoFs (HWND hwndDlg, unsigned __int64 startSector, __int64 num_sectors, void * dev, PCRYPTO_INFO cryptoInfo, BOOL quickFormat)
{
	int write_buf_cnt = 0;
	char sector[TC_MAX_VOLUME_SECTOR_SIZE], *write_buf;
	unsigned __int64 nSecNo = startSector;
	int retVal = 0;
	DWORD err;
	char temporaryKey[MASTER_KEYDATA_SIZE];
	char originalK2[MASTER_KEYDATA_SIZE];

	LARGE_INTEGER startOffset;
	LARGE_INTEGER newOffset;

	// Seek to start sector
	startOffset.QuadPart = startSector * FormatSectorSize;
	if (!SetFilePointerEx ((HANDLE) dev, startOffset, &newOffset, FILE_BEGIN)
		|| newOffset.QuadPart != startOffset.QuadPart)
	{
		return ERR_OS_ERROR;
	}

	write_buf = (char *)TCalloc (FormatWriteBufferSize);
	if (!write_buf)
		return ERR_OUTOFMEMORY;

	VirtualLock (temporaryKey, sizeof (temporaryKey));
	VirtualLock (originalK2, sizeof (originalK2));

	memset (sector, 0, sizeof (sector));

	// Remember the original secondary key (XTS mode) before generating a temporary one
	memcpy (originalK2, cryptoInfo->k2, sizeof (cryptoInfo->k2));

	/* Fill the rest of the data area with random data */

	if(!quickFormat)
	{
		/* Generate a random temporary key set to be used for "dummy" encryption that will fill
		the free disk space (data area) with random data.  This is necessary for plausible
		deniability of hidden volumes. */

		// Temporary master key
		if (!RandgetBytes (hwndDlg, temporaryKey, EAGetKeySize (cryptoInfo->ea), FALSE))
			goto fail;

		// Temporary secondary key (XTS mode)
		if (!RandgetBytes (hwndDlg, cryptoInfo->k2, sizeof cryptoInfo->k2, FALSE))
			goto fail;

		retVal = EAInit (cryptoInfo->ea, temporaryKey, cryptoInfo->ks);
		if (retVal != ERR_SUCCESS)
			goto fail;

		if (!EAInitMode (cryptoInfo))
		{
			retVal = ERR_MODE_INIT_FAILED;
			goto fail;
		}

		while (num_sectors--)
		{
			if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
				cryptoInfo) == FALSE)
				goto fail;
		}

		if (!FlushFormatWriteBuffer (dev, write_buf, &write_buf_cnt, &nSecNo, cryptoInfo))
			goto fail;
	}
	else
		nSecNo = num_sectors;

	UpdateProgressBar (nSecNo * FormatSectorSize);

	// Restore the original secondary key (XTS mode) in case NTFS format fails and the user wants to try FAT immediately
	memcpy (cryptoInfo->k2, originalK2, sizeof (cryptoInfo->k2));

	// Reinitialize the encryption algorithm and mode in case NTFS format fails and the user wants to try FAT immediately
	retVal = EAInit (cryptoInfo->ea, cryptoInfo->master_keydata, cryptoInfo->ks);
	if (retVal != ERR_SUCCESS)
		goto fail;
	if (!EAInitMode (cryptoInfo))
	{
		retVal = ERR_MODE_INIT_FAILED;
		goto fail;
	}

	burn (temporaryKey, sizeof(temporaryKey));
	burn (originalK2, sizeof(originalK2));
	VirtualUnlock (temporaryKey, sizeof (temporaryKey));
	VirtualUnlock (originalK2, sizeof (originalK2));
	TCfree (write_buf);

	return 0;

fail:
	err = GetLastError();

	burn (temporaryKey, sizeof(temporaryKey));
	burn (originalK2, sizeof(originalK2));
	VirtualUnlock (temporaryKey, sizeof (temporaryKey));
	VirtualUnlock (originalK2, sizeof (originalK2));
	TCfree (write_buf);

	SetLastError (err);
	return (retVal ? retVal : ERR_OS_ERROR);
}
예제 #2
0
// Creates a volume header in memory
int CreateVolumeHeaderInMemory (BOOL bBoot, char *header, int ea, int mode, Password *password,
		   int pkcs5_prf, char *masterKeydata, PCRYPTO_INFO *retInfo,
		   unsigned __int64 volumeSize, unsigned __int64 hiddenVolumeSize,
		   unsigned __int64 encryptedAreaStart, unsigned __int64 encryptedAreaLength, uint16 requiredProgramVersion, uint32 headerFlags, uint32 sectorSize, BOOL bWipeMode)
{
	unsigned char *p = (unsigned char *) header;
	static KEY_INFO keyInfo;

	int nUserKeyLen = password->Length;
	PCRYPTO_INFO cryptoInfo = crypto_open ();
	static char dk[MASTER_KEYDATA_SIZE];
	int x;
	int retVal = 0;
	int primaryKeyOffset;

	if (cryptoInfo == NULL)
		return ERR_OUTOFMEMORY;

	memset (header, 0, TC_VOLUME_HEADER_EFFECTIVE_SIZE);

	VirtualLock (&keyInfo, sizeof (keyInfo));
	VirtualLock (&dk, sizeof (dk));

	/* Encryption setup */

	if (masterKeydata == NULL)
	{
		// We have no master key data (creating a new volume) so we'll use the TrueCrypt RNG to generate them

		int bytesNeeded;

		switch (mode)
		{
		case LRW:
		case CBC:
		case INNER_CBC:
		case OUTER_CBC:

			// Deprecated/legacy modes of operation
			bytesNeeded = LEGACY_VOL_IV_SIZE + EAGetKeySize (ea);

			// In fact, this should never be the case since volumes being newly created are not
			// supposed to use any deprecated mode of operation.
			TC_THROW_FATAL_EXCEPTION;
			break;

		default:
			bytesNeeded = EAGetKeySize (ea) * 2;	// Size of primary + secondary key(s)
		}

		if (!RandgetBytes (keyInfo.master_keydata, bytesNeeded, TRUE))
			return ERR_CIPHER_INIT_WEAK_KEY;
	}
	else
	{
		// We already have existing master key data (the header is being re-encrypted)
		memcpy (keyInfo.master_keydata, masterKeydata, MASTER_KEYDATA_SIZE);
	}

	// User key 
	memcpy (keyInfo.userKey, password->Text, nUserKeyLen);
	keyInfo.keyLength = nUserKeyLen;
	keyInfo.noIterations = get_pkcs5_iteration_count (pkcs5_prf, bBoot);

	// User selected encryption algorithm
	cryptoInfo->ea = ea;

	// Mode of operation
	cryptoInfo->mode = mode;

	// Salt for header key derivation
	if (!RandgetBytes (keyInfo.salt, PKCS5_SALT_SIZE, !bWipeMode))
		return ERR_CIPHER_INIT_WEAK_KEY; 

	// PBKDF2 (PKCS5) is used to derive primary header key(s) and secondary header key(s) (XTS) from the password/keyfiles
	switch (pkcs5_prf)
	{
	case SHA512:
		derive_key_sha512 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
			PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
		break;

	case SHA1:
		// Deprecated/legacy
		derive_key_sha1 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
			PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
		break;

	case RIPEMD160:
		derive_key_ripemd160 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
			PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
		break;

	case WHIRLPOOL:
		derive_key_whirlpool (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
			PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
		break;

	default:		
		// Unknown/wrong ID
		TC_THROW_FATAL_EXCEPTION;
	} 

	/* Header setup */

	// Salt
	mputBytes (p, keyInfo.salt, PKCS5_SALT_SIZE);	

	// Magic
	mputLong (p, 0x54525545);

	// Header version
	mputWord (p, VOLUME_HEADER_VERSION);
	cryptoInfo->HeaderVersion = VOLUME_HEADER_VERSION;

	// Required program version to handle this volume
	switch (mode)
	{
	case LRW:
		// Deprecated/legacy
		mputWord (p, 0x0410);
		break;
	case OUTER_CBC:
	case INNER_CBC:
		// Deprecated/legacy
		mputWord (p, 0x0300);
		break;
	case CBC:
		// Deprecated/legacy
		mputWord (p, hiddenVolumeSize > 0 ? 0x0300 : 0x0100);
		break;
	default:
		mputWord (p, requiredProgramVersion != 0 ? requiredProgramVersion : TC_VOLUME_MIN_REQUIRED_PROGRAM_VERSION);
	}

	// CRC of the master key data
	x = GetCrc32(keyInfo.master_keydata, MASTER_KEYDATA_SIZE);
	mputLong (p, x);

	// Reserved fields
	p += 2 * 8;

	// Size of hidden volume (if any)
	cryptoInfo->hiddenVolumeSize = hiddenVolumeSize;
	mputInt64 (p, cryptoInfo->hiddenVolumeSize);

	cryptoInfo->hiddenVolume = cryptoInfo->hiddenVolumeSize != 0;

	// Volume size
	cryptoInfo->VolumeSize.Value = volumeSize;
	mputInt64 (p, volumeSize);

	// Encrypted area start
	cryptoInfo->EncryptedAreaStart.Value = encryptedAreaStart;
	mputInt64 (p, encryptedAreaStart);

	// Encrypted area size
	cryptoInfo->EncryptedAreaLength.Value = encryptedAreaLength;
	mputInt64 (p, encryptedAreaLength);

	// Flags
	cryptoInfo->HeaderFlags = headerFlags;
	mputLong (p, headerFlags);

	// Sector size
	if (sectorSize < TC_MIN_VOLUME_SECTOR_SIZE
		|| sectorSize > TC_MAX_VOLUME_SECTOR_SIZE
		|| sectorSize % ENCRYPTION_DATA_UNIT_SIZE != 0)
	{
		TC_THROW_FATAL_EXCEPTION;
	}

	cryptoInfo->SectorSize = sectorSize;
	mputLong (p, sectorSize);

	// CRC of the header fields
	x = GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC);
	p = header + TC_HEADER_OFFSET_HEADER_CRC;
	mputLong (p, x);

	// The master key data
	memcpy (header + HEADER_MASTER_KEYDATA_OFFSET, keyInfo.master_keydata, MASTER_KEYDATA_SIZE);


	/* Header encryption */

	switch (mode)
	{
	case LRW:
	case CBC:
	case INNER_CBC:
	case OUTER_CBC:

		// For LRW (deprecated/legacy), the tweak key
		// For CBC (deprecated/legacy), the IV/whitening seed
		memcpy (cryptoInfo->k2, dk, LEGACY_VOL_IV_SIZE);
		primaryKeyOffset = LEGACY_VOL_IV_SIZE;
		break;

	default:
		// The secondary key (if cascade, multiple concatenated)
		memcpy (cryptoInfo->k2, dk + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea));
		primaryKeyOffset = 0;
	}

	retVal = EAInit (cryptoInfo->ea, dk + primaryKeyOffset, cryptoInfo->ks);
	if (retVal != ERR_SUCCESS)
		return retVal;

	// Mode of operation
	if (!EAInitMode (cryptoInfo))
		return ERR_OUTOFMEMORY;


	// Encrypt the entire header (except the salt)
	EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET,
		HEADER_ENCRYPTED_DATA_SIZE,
		cryptoInfo);


	/* cryptoInfo setup for further use (disk format) */

	// Init with the master key(s) 
	retVal = EAInit (cryptoInfo->ea, keyInfo.master_keydata + primaryKeyOffset, cryptoInfo->ks);
	if (retVal != ERR_SUCCESS)
		return retVal;

	memcpy (cryptoInfo->master_keydata, keyInfo.master_keydata, MASTER_KEYDATA_SIZE);

	switch (cryptoInfo->mode)
	{
	case LRW:
	case CBC:
	case INNER_CBC:
	case OUTER_CBC:

		// For LRW (deprecated/legacy), the tweak key
		// For CBC (deprecated/legacy), the IV/whitening seed
		memcpy (cryptoInfo->k2, keyInfo.master_keydata, LEGACY_VOL_IV_SIZE);
		break;

	default:
		// The secondary master key (if cascade, multiple concatenated)
		memcpy (cryptoInfo->k2, keyInfo.master_keydata + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea));
	}

	// Mode of operation
	if (!EAInitMode (cryptoInfo))
		return ERR_OUTOFMEMORY;


#ifdef VOLFORMAT
	if (showKeys && !bInPlaceEncNonSys)
	{
		BOOL dots3 = FALSE;
		int i, j;

		j = EAGetKeySize (ea);

		if (j > NBR_KEY_BYTES_TO_DISPLAY)
		{
			dots3 = TRUE;
			j = NBR_KEY_BYTES_TO_DISPLAY;
		}

		MasterKeyGUIView[0] = 0;
		for (i = 0; i < j; i++)
		{
			char tmp2[8] = {0};
			sprintf (tmp2, "%02X", (int) (unsigned char) keyInfo.master_keydata[i + primaryKeyOffset]);
			strcat (MasterKeyGUIView, tmp2);
		}

		HeaderKeyGUIView[0] = 0;
		for (i = 0; i < NBR_KEY_BYTES_TO_DISPLAY; i++)
		{
			char tmp2[8];
			sprintf (tmp2, "%02X", (int) (unsigned char) dk[primaryKeyOffset + i]);
			strcat (HeaderKeyGUIView, tmp2);
		}

		if (dots3)
		{
			DisplayPortionsOfKeys (hHeaderKey, hMasterKey, HeaderKeyGUIView, MasterKeyGUIView, !showKeys);
		}
		else
		{
			SendMessage (hMasterKey, WM_SETTEXT, 0, (LPARAM) MasterKeyGUIView);
			SendMessage (hHeaderKey, WM_SETTEXT, 0, (LPARAM) HeaderKeyGUIView);
		}
	}
#endif	// #ifdef VOLFORMAT

	burn (dk, sizeof(dk));
	burn (&keyInfo, sizeof (keyInfo));

	*retInfo = cryptoInfo;
	return 0;
}
예제 #3
0
/*
	ExpandVolume

	Sets the volume size in the volume header (and backup header) to a larger value,
	and resizes the filesystem within the volume (only NTFS supported)

	Parameters:

		hwndDlg : HWND
			[in] handle to progress dialog

		lpszVolume : char *
			[in] Pointer to a string that contains the path to the truecrypt volume

		pVolumePassword : Password *
			[in] Pointer to the volume password

		newHostSize : uint64
			[in] new value of the volume host size (can be zero for devices,
			     which means the volume should use all space of the host device)

		initFreeSpace : BOOL
			[in] if true, the new volume space will be initalized with random data

	Return value:

		int with Truecrypt error code (ERR_SUCCESS on success)

	Remarks: a lot of code is from TrueCrypt 'Common\Password.c' :: ChangePwd()

*/
static int ExpandVolume (HWND hwndDlg, wchar_t *lpszVolume, Password *pVolumePassword, int VolumePkcs5, int VolumePim, uint64 newHostSize, BOOL initFreeSpace)
{
    int nDosLinkCreated = 1, nStatus = ERR_OS_ERROR;
    wchar_t szDiskFile[TC_MAX_PATH], szCFDevice[TC_MAX_PATH];
    wchar_t szDosDevice[TC_MAX_PATH];
    char buffer[TC_VOLUME_HEADER_EFFECTIVE_SIZE];
    PCRYPTO_INFO cryptoInfo = NULL, ci = NULL;
    void *dev = INVALID_HANDLE_VALUE;
    DWORD dwError;
    BOOL bDevice;
    uint64 hostSize=0, newDataAreaSize, currentVolSize;
    DWORD HostSectorSize;
    FILETIME ftCreationTime;
    FILETIME ftLastWriteTime;
    FILETIME ftLastAccessTime;
    BOOL bTimeStampValid = FALSE;
    LARGE_INTEGER headerOffset;
    BOOL backupHeader;
    byte *wipeBuffer = NULL;
    uint32 workChunkSize = TC_VOLUME_HEADER_GROUP_SIZE;

    if (pVolumePassword->Length == 0) return -1;

    WaitCursor ();

    CreateFullVolumePath (szDiskFile, sizeof(szDiskFile), lpszVolume, &bDevice);

    if (bDevice == FALSE)
    {
        wcscpy (szCFDevice, szDiskFile);
    }
    else
    {
        nDosLinkCreated = FakeDosNameForDevice (szDiskFile, szDosDevice, sizeof(szDosDevice), szCFDevice, sizeof(szCFDevice), FALSE);

        if (nDosLinkCreated != 0) // note: nStatus == ERR_OS_ERROR
            goto error;
    }

    dev = CreateFile (szCFDevice, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);

    if (dev == INVALID_HANDLE_VALUE)
        goto error;

    if (bDevice)
    {
        /* This is necessary to determine the hidden volume header offset */

        if (dev == INVALID_HANDLE_VALUE)
        {
            goto error;
        }
        else
        {
            PARTITION_INFORMATION diskInfo;
            DWORD dwResult;
            BOOL bResult;

            bResult = GetPartitionInfo (lpszVolume, &diskInfo);

            if (bResult)
            {
                hostSize = diskInfo.PartitionLength.QuadPart;
                HostSectorSize = TC_SECTOR_SIZE_FILE_HOSTED_VOLUME; //TO DO: get the real host disk sector size
            }
            else
            {
                DISK_GEOMETRY driveInfo;

                bResult = DeviceIoControl (dev, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
                                           &driveInfo, sizeof (driveInfo), &dwResult, NULL);

                if (!bResult)
                    goto error;

                hostSize = driveInfo.Cylinders.QuadPart * driveInfo.BytesPerSector *
                           driveInfo.SectorsPerTrack * driveInfo.TracksPerCylinder;

                HostSectorSize = driveInfo.BytesPerSector;
            }

            if (hostSize == 0)
            {
                nStatus = ERR_VOL_SIZE_WRONG;
                goto error;
            }
        }
    }
    else
    {
        LARGE_INTEGER fileSize;
        if (!GetFileSizeEx (dev, &fileSize))
        {
            nStatus = ERR_OS_ERROR;
            goto error;
        }

        hostSize = fileSize.QuadPart;
        HostSectorSize = TC_SECTOR_SIZE_FILE_HOSTED_VOLUME; //TO DO: get the real host disk sector size
    }

    if (Randinit ())
    {
        if (CryptoAPILastError == ERROR_SUCCESS)
            nStatus = ERR_RAND_INIT_FAILED;
        else
            nStatus = ERR_CAPI_INIT_FAILED;
        goto error;
    }

    if (!bDevice && bPreserveTimestamp)
    {
        /* Remember the container modification/creation date and time, (used to reset file date and time of
        file-hosted volumes after password change (or attempt to), in order to preserve plausible deniability
        of hidden volumes (last password change time is stored in the volume header). */

        if (GetFileTime ((HANDLE) dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime) == 0)
        {
            bTimeStampValid = FALSE;
            MessageBoxW (hwndDlg, GetString ("GETFILETIME_FAILED_PW"), lpszTitle, MB_OK | MB_ICONEXCLAMATION);
        }
        else
            bTimeStampValid = TRUE;
    }

    // Seek the volume header
    headerOffset.QuadPart = TC_VOLUME_HEADER_OFFSET;

    if (!SetFilePointerEx ((HANDLE) dev, headerOffset, NULL, FILE_BEGIN))
    {
        nStatus = ERR_OS_ERROR;
        goto error;
    }

    /* Read in volume header */
    nStatus = _lread ((HFILE) dev, buffer, sizeof (buffer));
    if (nStatus != sizeof (buffer))
    {
        // Windows may report EOF when reading sectors from the last cluster of a device formatted as NTFS
        memset (buffer, 0, sizeof (buffer));
    }

    /* Try to decrypt the header */

    nStatus = ReadVolumeHeader (FALSE, buffer, pVolumePassword, VolumePkcs5, VolumePim, FALSE, &cryptoInfo, NULL);
    if (nStatus == ERR_CIPHER_INIT_WEAK_KEY)
        nStatus = 0;	// We can ignore this error here

    if (nStatus != 0)
    {
        cryptoInfo = NULL;
        goto error;
    }

    if (cryptoInfo->HeaderFlags & TC_HEADER_FLAG_ENCRYPTED_SYSTEM)
    {
        nStatus = ERR_SYS_HIDVOL_HEAD_REENC_MODE_WRONG;
        goto error;
    }

    if (bDevice && newHostSize == 0)
    {
        // this means we shall take all host space as new volume size
        newHostSize = hostSize;
    }

    if ( newHostSize % cryptoInfo->SectorSize != 0  || newHostSize > TC_MAX_VOLUME_SIZE || (bDevice && newHostSize > hostSize) )
    {
        // 1. must be multiple of sector size
        // 2. truecrypt volume size limit
        // 3. for devices volume size can't be larger than host size
        cryptoInfo = NULL;
        nStatus = ERR_PARAMETER_INCORRECT;
        goto error;
    }

    newDataAreaSize = GetVolumeDataAreaSize (newHostSize, cryptoInfo->LegacyVolume);

    if (cryptoInfo->LegacyVolume)
    {
        if (bDevice)
        {
            if (initFreeSpace)
            {
                // unsupported
                cryptoInfo = NULL;
                nStatus = ERR_PARAMETER_INCORRECT;
                goto error;
            }
            else
            {
                // note: dummy value (only used for parameter checks)
                cryptoInfo->VolumeSize.Value = newDataAreaSize - TC_MINVAL_FS_EXPAND;
            }
        }
        else
        {
            cryptoInfo->VolumeSize.Value = GetVolumeDataAreaSize (hostSize, TRUE);
        }
    }

    currentVolSize = GetVolumeSizeByDataAreaSize (cryptoInfo->VolumeSize.Value, cryptoInfo->LegacyVolume);

    if ( newDataAreaSize < cryptoInfo->VolumeSize.Value + TC_MINVAL_FS_EXPAND )
    {
        // shrinking a volume or enlarging by less then TC_MINVAL_FS_EXPAND is not allowed
        cryptoInfo = NULL;
        nStatus = ERR_PARAMETER_INCORRECT;
        goto error;
    }

    InitProgressBar ( newHostSize, currentVolSize, FALSE, FALSE, FALSE, TRUE);

    if (bVolTransformThreadCancel)
    {
        SetLastError(0);
        nStatus = ERR_USER_ABORT;
        goto error;
    }

    if (!bDevice) {
        LARGE_INTEGER liNewSize;

        liNewSize.QuadPart=(LONGLONG)newHostSize;

        // Preallocate the file
        if (!SetFilePointerEx (dev, liNewSize, NULL, FILE_BEGIN)
                || !SetEndOfFile (dev)
                || SetFilePointer (dev, 0, NULL, FILE_BEGIN) != 0)
        {
            nStatus = ERR_OS_ERROR;
            goto error;
        }
    }

    if (initFreeSpace)
    {
        uint64 startSector;
        int64 num_sectors;

        // fill new space with random data
        startSector = currentVolSize/HostSectorSize ;
        num_sectors = (newHostSize/HostSectorSize) - startSector;

        if (bDevice && !StartFormatWriteThread())
        {
            nStatus = ERR_OS_ERROR;
            goto error;
        }

        DebugAddProgressDlgStatus(hwndDlg, L"Writing random data to new space ...\r\n");

        SetFormatSectorSize(HostSectorSize);
        nStatus = FormatNoFs (hwndDlg, startSector, num_sectors, dev, cryptoInfo, FALSE);

        dwError = GetLastError();
        StopFormatWriteThread();
        SetLastError (dwError);
    }
    else
    {
        UpdateProgressBar(newHostSize);
    }

    if (nStatus != ERR_SUCCESS)
    {
        dwError = GetLastError();
        DebugAddProgressDlgStatus(hwndDlg, L"Error: failed to write random data ...\r\n");
        if ( !bDevice ) {
            // restore original size of the container file
            LARGE_INTEGER liOldSize;
            liOldSize.QuadPart=(LONGLONG)hostSize;
            if (!SetFilePointerEx (dev, liOldSize, NULL, FILE_BEGIN) || !SetEndOfFile (dev))
            {
                DebugAddProgressDlgStatus(hwndDlg, L"Warning: failed to restore original size of the container file\r\n");
            }
        }
        SetLastError (dwError);
        goto error;
    }

    RandSetHashFunction (cryptoInfo->pkcs5);

    // Re-encrypt the volume header forn non-legacy volumes: backup header first
    backupHeader = TRUE;
    headerOffset.QuadPart = TC_VOLUME_HEADER_OFFSET + newHostSize - TC_VOLUME_HEADER_GROUP_SIZE;

    /* note: updating the header is not neccessary for legay volumes */
    while ( !cryptoInfo->LegacyVolume )
    {
        if (backupHeader)
            DebugAddProgressDlgStatus(hwndDlg, L"Writing re-encrypted backup header ...\r\n");
        else
            DebugAddProgressDlgStatus(hwndDlg, L"Writing re-encrypted primary header ...\r\n");

        // Prepare new volume header
        nStatus = CreateVolumeHeaderInMemory (hwndDlg, FALSE,
                                              buffer,
                                              cryptoInfo->ea,
                                              cryptoInfo->mode,
                                              pVolumePassword,
                                              cryptoInfo->pkcs5,
                                              VolumePim,
                                              (char*)(cryptoInfo->master_keydata),
                                              &ci,
                                              newDataAreaSize,
                                              0, // hiddenVolumeSize
                                              cryptoInfo->EncryptedAreaStart.Value,
                                              newDataAreaSize,
                                              cryptoInfo->RequiredProgramVersion,
                                              cryptoInfo->HeaderFlags,
                                              cryptoInfo->SectorSize,
                                              TRUE ); // use slow poll

        if (ci != NULL)
            crypto_close (ci);

        if (nStatus != 0)
            goto error;

        if (!SetFilePointerEx ((HANDLE) dev, headerOffset, NULL, FILE_BEGIN))
        {
            nStatus = ERR_OS_ERROR;
            goto error;
        }

        nStatus = _lwrite ((HFILE) dev, buffer, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
        if (nStatus != TC_VOLUME_HEADER_EFFECTIVE_SIZE)
        {
            nStatus = ERR_OS_ERROR;
            goto error;
        }

        if ( ( backupHeader && !initFreeSpace )
                || ( bDevice
                     && !cryptoInfo->LegacyVolume
                     && !cryptoInfo->hiddenVolume
                     && cryptoInfo->HeaderVersion == 4	// BUG in TrueCrypt: doing this only for v4 make no sense
                     && (cryptoInfo->HeaderFlags & TC_HEADER_FLAG_NONSYS_INPLACE_ENC) != 0
                     && (cryptoInfo->HeaderFlags & ~TC_HEADER_FLAG_NONSYS_INPLACE_ENC) == 0 )
           )
        {
            //DebugAddProgressDlgStatus(hwndDlg, L"WriteRandomDataToReservedHeaderAreas() ...\r\n");
            nStatus = WriteRandomDataToReservedHeaderAreas (hwndDlg, dev, cryptoInfo, newDataAreaSize, !backupHeader, backupHeader);
            if (nStatus != ERR_SUCCESS)
                goto error;
        }

        FlushFileBuffers (dev);

        if (!backupHeader)
            break;

        backupHeader = FALSE;
        headerOffset.QuadPart = TC_VOLUME_HEADER_OFFSET; // offset for main header
    }

    /* header successfully updated */
    nStatus = ERR_SUCCESS;

    if (bVolTransformThreadCancel)
    {
        nStatus = ERR_USER_ABORT;
        goto error;
    }

    /* wipe old backup header */
    if ( !cryptoInfo->LegacyVolume )
    {
        byte wipeRandChars [TC_WIPE_RAND_CHAR_COUNT];
        byte wipeRandCharsUpdate [TC_WIPE_RAND_CHAR_COUNT];
        byte wipePass;
        UINT64_STRUCT unitNo;
        LARGE_INTEGER offset;
        WipeAlgorithmId wipeAlgorithm = TC_WIPE_35_GUTMANN;

        if (	!RandgetBytes (hwndDlg, wipeRandChars, TC_WIPE_RAND_CHAR_COUNT, TRUE)
                || !RandgetBytes (hwndDlg, wipeRandCharsUpdate, TC_WIPE_RAND_CHAR_COUNT, TRUE)
           )
        {
            nStatus = ERR_OS_ERROR;
            goto error;
        }

        DebugAddProgressDlgStatus(hwndDlg, L"Wiping old backup header ...\r\n");

        wipeBuffer = (byte *) TCalloc (workChunkSize);
        if (!wipeBuffer)
        {
            nStatus = ERR_OUTOFMEMORY;
            goto error;
        }

        offset.QuadPart = currentVolSize - TC_VOLUME_HEADER_GROUP_SIZE;
        unitNo.Value = offset.QuadPart;

        for (wipePass = 1; wipePass <= GetWipePassCount (wipeAlgorithm); ++wipePass)
        {
            if (!WipeBuffer (wipeAlgorithm, wipeRandChars, wipePass, wipeBuffer, workChunkSize))
            {
                ULONG i;
                for (i = 0; i < workChunkSize; ++i)
                {
                    wipeBuffer[i] = wipePass;
                }

                EncryptDataUnits (wipeBuffer, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, cryptoInfo);
                memcpy (wipeRandCharsUpdate, wipeBuffer, sizeof (wipeRandCharsUpdate));
            }

            if ( !SetFilePointerEx (dev, offset, NULL, FILE_BEGIN)
                    || _lwrite ((HFILE)dev, (LPCSTR)wipeBuffer, workChunkSize) == HFILE_ERROR
               )
            {
                // Write error
                DebugAddProgressDlgStatus(hwndDlg, L"Warning: Failed to wipe old backup header\r\n");
                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);
                if (wipePass == 1)
                    continue; // retry once
                // non-critical error - it's better to continue
                nStatus = ERR_SUCCESS;
                goto error;
            }
            FlushFileBuffers(dev);
            // we don't check FlushFileBuffers() return code, because it fails for devices
            // (same implementation in password.c - a bug or not ???)
        }

        burn (wipeRandChars, TC_WIPE_RAND_CHAR_COUNT);
        burn (wipeRandCharsUpdate, TC_WIPE_RAND_CHAR_COUNT);
    }

error:
    dwError = GetLastError ();

    if (wipeBuffer)
    {
        burn (wipeBuffer, workChunkSize);
        TCfree (wipeBuffer);
        wipeBuffer = NULL;
    }

    burn (buffer, sizeof (buffer));

    if (cryptoInfo != NULL)
        crypto_close (cryptoInfo);

    if (bTimeStampValid)
    {
        // Restore the container timestamp (to preserve plausible deniability of possible hidden volume).
        if (SetFileTime (dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime) == 0)
            MessageBoxW (hwndDlg, GetString ("SETFILETIME_FAILED_PW"), lpszTitle, MB_OK | MB_ICONEXCLAMATION);
    }

    if (dev != INVALID_HANDLE_VALUE)
        CloseHandle ((HANDLE) dev);

    if (nDosLinkCreated == 0)
        RemoveFakeDosName (szDiskFile, szDosDevice);

    RandStop (FALSE);

    if (bVolTransformThreadCancel)
        nStatus = ERR_USER_ABORT;

    SetLastError (dwError);

    if (nStatus == ERR_SUCCESS)
    {
        nStatus = ExtendFileSystem (hwndDlg, lpszVolume, pVolumePassword, VolumePkcs5, VolumePim, newDataAreaSize);
    }

    return nStatus;
}
예제 #4
0
// Writes randomly generated data to unused/reserved header areas.
// When bPrimaryOnly is TRUE, then only the primary header area (not the backup header area) is filled with random data.
// When bBackupOnly is TRUE, only the backup header area (not the primary header area) is filled with random data.
int WriteRandomDataToReservedHeaderAreas (HANDLE dev, CRYPTO_INFO *cryptoInfo, uint64 dataAreaSize, BOOL bPrimaryOnly, BOOL bBackupOnly)
{
	char temporaryKey[MASTER_KEYDATA_SIZE];
	char originalK2[MASTER_KEYDATA_SIZE];

	byte buf[TC_VOLUME_HEADER_GROUP_SIZE];

	LARGE_INTEGER offset;
	int nStatus = ERR_SUCCESS;
	DWORD dwError;
	DWORD bytesDone;
	BOOL backupHeaders = bBackupOnly;

	if (bPrimaryOnly && bBackupOnly)
		TC_THROW_FATAL_EXCEPTION;

	memcpy (originalK2, cryptoInfo->k2, sizeof (cryptoInfo->k2));

	while (TRUE)
	{
		// Temporary keys
		if (!RandgetBytes (temporaryKey, EAGetKeySize (cryptoInfo->ea), FALSE)
			|| !RandgetBytes (cryptoInfo->k2, sizeof (cryptoInfo->k2), FALSE))
		{
			nStatus = ERR_PARAMETER_INCORRECT; 
			goto final_seq;
		}

		nStatus = EAInit (cryptoInfo->ea, temporaryKey, cryptoInfo->ks);
		if (nStatus != ERR_SUCCESS)
			goto final_seq;

		if (!EAInitMode (cryptoInfo))
		{
			nStatus = ERR_MODE_INIT_FAILED;
			goto final_seq;
		}

		offset.QuadPart = backupHeaders ? dataAreaSize + TC_VOLUME_HEADER_GROUP_SIZE : TC_VOLUME_HEADER_OFFSET;

		if (!SetFilePointerEx (dev, offset, NULL, FILE_BEGIN))
		{
			nStatus = ERR_OS_ERROR;
			goto final_seq;
		}

		if (!ReadFile (dev, buf, sizeof (buf), &bytesDone, NULL))
		{
			nStatus = ERR_OS_ERROR;
			goto final_seq;
		}

		if (bytesDone < TC_VOLUME_HEADER_EFFECTIVE_SIZE)
		{
			SetLastError (ERROR_INVALID_PARAMETER);
			nStatus = ERR_OS_ERROR;
			goto final_seq;
		}

		EncryptBuffer (buf + TC_VOLUME_HEADER_EFFECTIVE_SIZE, sizeof (buf) - TC_VOLUME_HEADER_EFFECTIVE_SIZE, cryptoInfo);

		if (!SetFilePointerEx (dev, offset, NULL, FILE_BEGIN))
		{
			nStatus = ERR_OS_ERROR;
			goto final_seq;
		}

		if (!WriteFile (dev, buf, sizeof (buf), &bytesDone, NULL))
		{
			nStatus = ERR_OS_ERROR;
			goto final_seq;
		}

		if (bytesDone != sizeof (buf))
		{
			nStatus = ERR_PARAMETER_INCORRECT;
			goto final_seq;
		}

		if (backupHeaders || bPrimaryOnly)
			break;

		backupHeaders = TRUE;
	}

	memcpy (cryptoInfo->k2, originalK2, sizeof (cryptoInfo->k2));

	nStatus = EAInit (cryptoInfo->ea, cryptoInfo->master_keydata, cryptoInfo->ks);
	if (nStatus != ERR_SUCCESS)
		goto final_seq;

	if (!EAInitMode (cryptoInfo))
	{
		nStatus = ERR_MODE_INIT_FAILED;
		goto final_seq;
	}

final_seq:

	dwError = GetLastError();

	burn (temporaryKey, sizeof (temporaryKey));
	burn (originalK2, sizeof (originalK2));

	if (nStatus != ERR_SUCCESS)
		SetLastError (dwError);

	return nStatus;
}