-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New features added to VeraCryptFormat.dll #1659
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,6 +27,8 @@ | |
| #include <mutex> | ||
| #include <atomic> | ||
| #include <Strsafe.h> | ||
| #include <array> | ||
| #include <Shlwapi.h> | ||
|
|
||
| #include "Dlgcode.h" | ||
| #include "Crypto.h" | ||
|
|
@@ -73,6 +75,39 @@ extern "C" DWORD GetFormatSectorSize(); | |
| void InitApp (HINSTANCE hInstance, wchar_t *lpszCommandLine); | ||
| void cleanup (); | ||
|
|
||
| constexpr std::array<const wchar_t*, 14> VolumeEncryptionAlgorithmOptions = std::array<const wchar_t*, 14>{ | ||
| L"AES", | ||
| L"Serpent", | ||
| L"Twofish", | ||
| L"Camellia", | ||
| L"Kuznyechik", | ||
| L"Serpent(Twofish(AES))", | ||
| L"Serpent(AES)", | ||
| L"AES(Twofish(Serpent))", | ||
| L"Twofish(Serpent)", | ||
| L"Camellia(Kuznyechik)", | ||
| L"Kuznyechik(Twofish)", | ||
| L"Camellia(Serpent)", | ||
| L"Kuznyechik(AES)", | ||
| L"Kuznyechik(Serpent(Camellia))", | ||
| }; | ||
|
|
||
| constexpr std::array<const wchar_t*, 5> HashAlgorithmOptions = std::array<const wchar_t*, 5>{ | ||
| L"SHA-512", | ||
| L"SHA-256", | ||
| L"RIPEMD-160", | ||
| L"Whirlpool", | ||
| L"BLAKE2s-256" | ||
| }; | ||
|
|
||
| constexpr std::array<const wchar_t*, 5> FileSystemFormatOptions = std::array<const wchar_t*, 5>{ | ||
| L"NTFS", | ||
| L"FAT", | ||
| L"ExFAT", | ||
| L"ReFS", | ||
| L"None" | ||
| }; | ||
|
|
||
| // Global mutex to ensure that volume creation operations are serialized, | ||
| // as the underlying code uses extensive global state. | ||
| static std::mutex g_sdkMutex; | ||
|
|
@@ -184,15 +219,18 @@ static int CreateVolumeInternal(const VeraCryptFormatOptions* options) | |
|
|
||
| // --- Setup VeraCrypt's global state from our options struct --- | ||
| bDevice = options->isDevice; | ||
| nVolumeSize = options->size; | ||
| if (!options->isDevice) { | ||
| nVolumeSize = options->size * (options->sizeMeasureUnity == SizeMeasureUnity::Kilobytes ? | ||
| 1024 : options->sizeMeasureUnity == SizeMeasureUnity::Megabytes ? 1024 * 1024 : 1024 * 1024 * 1024); | ||
| } | ||
|
|
||
| nVolumeEA = MapEncryptionAlgorithm(options->encryptionAlgorithm); | ||
| nVolumeEA = MapEncryptionAlgorithm(VolumeEncryptionAlgorithmOptions[static_cast<int>(options->encryptionAlgorithm)]); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This indexes a fixed array using a public enum value without bounds checking. Since this is a C ABI, callers can pass any integer value, not only valid enum constants. An invalid value here can read out of bounds before The same issue exists for |
||
| if (nVolumeEA == 0) return VCF_ERROR_INVALID_ENCRYPTION_ALGORITHM; | ||
|
|
||
| hash_algo = MapHashAlgorithm(options->hashAlgorithm); | ||
| hash_algo = MapHashAlgorithm(HashAlgorithmOptions[static_cast<int>(options->hashAlgorithm)]); | ||
| if (hash_algo == 0) return VCF_ERROR_INVALID_HASH_ALGORITHM; | ||
|
|
||
| fileSystem = MapFilesystem(options->filesystem); | ||
| fileSystem = MapFilesystem(FileSystemFormatOptions[static_cast<int>(options->filesystem)]); | ||
| if (fileSystem == -1) return VCF_ERROR_INVALID_FILESYSTEM; | ||
|
|
||
| volumePim = options->pim; | ||
|
|
@@ -332,7 +370,6 @@ static int CreateVolumeInternal(const VeraCryptFormatOptions* options) | |
| } | ||
| } | ||
|
|
||
|
|
||
| // --- Public DLL Exported Functions --- | ||
|
|
||
| extern "C" | ||
|
|
@@ -378,6 +415,161 @@ extern "C" | |
| return CreateVolumeInternal(options); | ||
| } | ||
|
|
||
| VCF_API int __cdecl VeraCryptMount(const VeraCryptMountOptions* options) { | ||
| if (!g_isInitialized) | ||
| { | ||
| return VCF_ERROR_NOT_INITIALIZED; | ||
| } | ||
|
|
||
| // Lock the mutex to protect the global state used by VeraCrypt's format code | ||
| std::lock_guard<std::mutex> lock(g_sdkMutex); | ||
|
|
||
| finally_do({ | ||
| // Clean up all sensitive data from globals | ||
| WipePasswordsAndKeyfiles(true); | ||
| // Reset globals to default state | ||
| KeyFileRemoveAll(&FirstKeyFile); | ||
| }); | ||
|
|
||
| if (!IsDriveAvailable(static_cast<int>(options->letter))) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Please validate |
||
| return VCF_ERROR_DRIVE_LETTER_UNAVIABLE; | ||
| } | ||
|
|
||
| MountOptions mountOptions = { 0 }; | ||
|
|
||
| if (options->password) | ||
| { | ||
| if (!CheckPasswordLength(NULL, (int)strlen(options->password), options->pim, FALSE, 0, TRUE, TRUE)) | ||
| { | ||
| return VCF_ERROR_PASSWORD_POLICY; | ||
| } | ||
| strcpy_s((char*)volumePassword.Text, sizeof(volumePassword.Text), options->password); | ||
| volumePassword.Length = (unsigned __int32)strlen(options->password); | ||
| } | ||
| else | ||
| { | ||
| volumePassword.Text[0] = 0; | ||
| volumePassword.Length = 0; | ||
| } | ||
|
|
||
| if (options->protectedHidVolPassword) { | ||
| if (!CheckPasswordLength(NULL, (int)strlen(options->protectedHidVolPassword), options->pim, FALSE, 0, TRUE, TRUE)) { | ||
| return VCF_ERROR_PASSWORD_POLICY; | ||
| } | ||
| strcpy_s((char*)mountOptions.ProtectedHidVolPassword.Text, sizeof(mountOptions.ProtectedHidVolPassword.Text), options->protectedHidVolPassword); | ||
| mountOptions.ProtectedHidVolPassword.Length = (unsigned __int32)strlen(options->protectedHidVolPassword); | ||
| } | ||
| else { | ||
| mountOptions.ProtectedHidVolPassword.Text[0] = 0; | ||
| mountOptions.ProtectedHidVolPassword.Length = 0; | ||
| } | ||
|
|
||
| FirstKeyFile = nullptr; | ||
| if (options->keyfiles) | ||
| { | ||
| for (int i = 0; options->keyfiles[i] != nullptr; ++i) | ||
| { | ||
| KeyFile* kf = (KeyFile*)malloc(sizeof(KeyFile)); | ||
| if (!kf) | ||
| { | ||
| KeyFileRemoveAll(&FirstKeyFile); | ||
| return VCF_ERROR_OUT_OF_MEMORY; | ||
| } | ||
| StringCbCopyW(kf->FileName, sizeof(kf->FileName), options->keyfiles[i]); | ||
| FirstKeyFile = KeyFileAdd(FirstKeyFile, kf); | ||
| } | ||
| } | ||
|
|
||
| if (!KeyFilesApply(NULL, &volumePassword, FirstKeyFile, NULL)) | ||
| { | ||
| return VCF_ERROR_KEYFILE_ERROR; | ||
| } | ||
| mountOptions.DisableMountManager = options->DisableMountManager; | ||
| StringCbCopyW(mountOptions.Label, sizeof(mountOptions.Label), options->Label); | ||
| mountOptions.PartitionInInactiveSysEncScope = options->PartitionInInactiveSysEncScope; | ||
| mountOptions.PreserveTimestamp = options->PreserveTimestamp; | ||
| mountOptions.ProtectedHidVolPim = options->ProtectedHidVolPim; | ||
| mountOptions.ProtectedHidVolPkcs5Prf = options->ProtectedHidVolPkcs5Prf; | ||
| mountOptions.ProtectHiddenVolume = options->ProtectHiddenVolume; | ||
| mountOptions.ReadOnly = options->ReadOnly; | ||
| mountOptions.RecoveryMode = options->RecoveryMode; | ||
| mountOptions.Removable = options->Removable; | ||
| mountOptions.SkipCachedPasswords = options->SkipCachedPasswords; | ||
| mountOptions.UseBackupHeader = options->UseBackupHeader; | ||
|
|
||
| int result = MountVolume(NULL, static_cast<int>(options->letter), options->path, &volumePassword, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Please copy |
||
| options->autoDetectEncryptionAlgorithm ? 0 : static_cast<int>(options->encryptionAlgorithm), | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This passes an encryption algorithm enum where The mount API should expose a PRF/hash option, or pass |
||
| options->pim, options->cachePassword, options->cachePim, options->sharedAccess, &mountOptions, | ||
| TRUE, TRUE | ||
| ); | ||
| if (options->sharedAccess) | ||
| return result == 2 ? VCF_SUCCESS : result; | ||
| return result == 1 ? VCF_SUCCESS : result; | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This maps mount failures to Please map |
||
|
|
||
| VCF_API int __cdecl VeraCryptDismount(DriveLetter letter, BOOL force) { | ||
| if (!g_isInitialized) | ||
| { | ||
| return VCF_ERROR_NOT_INITIALIZED; | ||
| } | ||
|
|
||
| // Lock the mutex to protect the global state used by VeraCrypt's format code | ||
| std::lock_guard<std::mutex> lock(g_sdkMutex); | ||
|
|
||
| return UnmountVolume(NULL, static_cast<int>(letter), force) == TRUE ? VCF_SUCCESS : VCF_ERROR_GENERIC; | ||
| } | ||
|
|
||
| VCF_API int __cdecl GetAbsolutePath(const wchar_t* relativePath, wchar_t* absolutePath, DWORD absolutePathSize) | ||
| { | ||
| if (!relativePath || !absolutePath || absolutePathSize == 0) | ||
| { | ||
| SetLastError(ERROR_INVALID_PARAMETER); | ||
| return VCF_ERROR_FULL_PATH_GETTING_ERROR; | ||
| } | ||
|
|
||
| absolutePath[0] = L'\0'; | ||
|
|
||
| DWORD requiredSize; | ||
|
|
||
| requiredSize = GetFullPathNameW(relativePath, 0, NULL, NULL); | ||
| if (requiredSize == 0) | ||
| { | ||
| return VCF_ERROR_FULL_PATH_GETTING_ERROR; | ||
| } | ||
|
|
||
| if (requiredSize > absolutePathSize) | ||
| { | ||
| SetLastError(ERROR_INSUFFICIENT_BUFFER); | ||
| return VCF_ERROR_FULL_PATH_GETTING_ERROR; | ||
| } | ||
|
|
||
| DWORD result = GetFullPathNameW(relativePath, absolutePathSize, absolutePath, NULL); | ||
| if (result == 0 || result >= absolutePathSize) | ||
| { | ||
| return VCF_ERROR_FULL_PATH_GETTING_ERROR; | ||
| } | ||
|
|
||
| return VCF_SUCCESS; | ||
| } | ||
|
|
||
| VCF_API int __cdecl GetDevicePath(DriveLetter letter, wchar_t* devicePath, DWORD devicePathSize) | ||
| { | ||
| if (!devicePath || devicePathSize == 0) | ||
| { | ||
| SetLastError(ERROR_INVALID_PARAMETER); | ||
| return VCF_ERROR_FULL_PATH_GETTING_ERROR; | ||
| } | ||
| devicePath[0] = L'\0'; | ||
|
|
||
| wchar_t drive[4] = { static_cast<wchar_t>(L'A' + static_cast<int>(letter)), L':', L'\0' }; | ||
| if (QueryDosDeviceW(drive, devicePath, devicePathSize) == 0) | ||
| { | ||
| // Error, possibly insufficient buffer | ||
| return VCF_ERROR_FULL_PATH_GETTING_ERROR; | ||
| } | ||
| return VCF_SUCCESS; | ||
| } | ||
|
|
||
| BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) | ||
| { | ||
| switch (fdwReason) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This multiplication can overflow
uint64_tbefore the later size checks run. For example, a largeoptions->sizevalue withGigabytescan wrap to a small value and pass subsequent validation incorrectly.Please validate
sizeMeasureUnity, checkoptions->size <= UINT64_MAX / multiplier, and update the public comment becausesizeis no longer always expressed in bytes.