#include #include #include #include #include namespace winrt { using namespace winrt::Windows::Foundation; using namespace winrt::Windows::Security::DataProtection; using namespace winrt::Windows::Storage; using namespace winrt::Windows::Storage::Streams; } void usage() { std::wcout << LR"(PersonalDataEncryption sample usage. PersonalDataEncryption.exe file Protect a file to a protection level. Path must be a fully-qualified path. PersonalDataEncryption.exe folder Protect a folder to a protection level. Path must be a fully-qualified path. PersonalDataEncryption.exe memory Protect a memory buffer to a protection level. For both options, the following protection levels are supported: Level 0: No protection (always available). Level 1: Available after first unlock. Level 2: Avaialble when unlocked. Examples: Protect a file to level 1: PersonalDataEncryption.exe file 1 C:\Users\Abby\Documents\file.txt Remove protection from a folder: PersonalDataEncryption.exe folder 1 C:\Users\Abby\Documents\Party Protect a string to level 2: PersonalDataEncryption.exe memory 2 "hello, world!" )"; } void ProtectItem(winrt::UserDataProtectionManager const& manager, winrt::UserDataAvailability availability, winrt::IStorageItem const& item) { auto status = manager.ProtectStorageItemAsync(item, availability).get(); wchar_t const* message; switch (status) { case winrt::UserDataStorageItemProtectionStatus::Succeeded: message = L"Succeeded"; break; case winrt::UserDataStorageItemProtectionStatus::NotProtectable: message = L"Not protectable"; break; case winrt::UserDataStorageItemProtectionStatus::DataUnavailable: message = L"Data unavailable"; break; default: message = L"Unknown failure"; break; } std::wcout << L"Protecting " << std::wstring_view(item.Path()) << L" to level " << static_cast(availability) << L": " << message << L"\n"; } void ProtectFile(winrt::UserDataProtectionManager const& manager, winrt::hstring const& path, winrt::UserDataAvailability availability) { winrt::IStorageItem item; try { item = winrt::StorageFile::GetFileFromPathAsync(path).get(); } catch (...) { std::wcout << L"Error getting StorageFile: " << std::wstring_view(winrt::to_message()) << L"\n"; } ProtectItem(manager, availability, item); } // Note that setting the availability of a folder establishes the availability for any new items // created in that folder, but it does not affect the availability of existing items in the folder. // If you want to change the availability of an entire folder tree, you should first call // ProtectStorageItemAsync to protect the folder (so that any new items are suitably protected), // and then recursively protect all the files and subfolders inside that folder. void ProtectFolder(winrt::UserDataProtectionManager const& manager, winrt::hstring const& path, winrt::UserDataAvailability availability) { winrt::IStorageItem item; try { item = winrt::StorageFolder::GetFolderFromPathAsync(path).get(); } catch (...) { std::wcout << L"Error getting StorageFile: " << std::wstring_view(winrt::to_message()) << L"\n"; } ProtectItem(manager, availability, item); } void ProtectMemory(winrt::UserDataProtectionManager const& manager, winrt::hstring const& message, winrt::UserDataAvailability availability) { // Convert the string to a Buffer. auto bufferSize = message.size() * static_cast(sizeof(wchar_t)); auto buffer = winrt::Buffer(bufferSize); memcpy_s(buffer.data(), bufferSize, message.c_str(), bufferSize); buffer.Length(bufferSize); // Protect the buffer. auto protectedBuffer = manager.ProtectBufferAsync(buffer, availability).get(); // Zero out the original buffer to ensure it holds no data. memset(buffer.data(), 0, bufferSize); // Free the original buffer and retain the protected buffer. buffer = nullptr; std::wcout << L"Memory buffer has been protected.\n" << L"Press Enter to unprotect it.\n"; std::cin.get(); // Now unprotect the buffer to recover the string. auto result = manager.UnprotectBufferAsync(protectedBuffer).get(); winrt::UserDataBufferUnprotectStatus status = result.Status(); winrt::IBuffer unprotectedBuffer = result.UnprotectedBuffer(); switch (status) { case winrt::UserDataBufferUnprotectStatus::Succeeded: // Extract the string from the unprotected buffer. std::wcout << L"Original message: " << std::wstring_view(reinterpret_cast(unprotectedBuffer.data()), unprotectedBuffer.Length() / sizeof(wchar_t)) << L"\n"; break; case winrt::UserDataBufferUnprotectStatus::Unavailable: std::wcout << L"Buffer cannot be unprotected at this time.\n"; break; default: std::wcout << L"Unexpected error when unprotecting buffer.\n"; break; } } void Run(int argc, wchar_t** argv) { if (argc != 4) { usage(); return; } wchar_t* end; auto availability = static_cast(wcstoul(argv[2], &end, 10)); if (*end != L'\0') { // Not an integer. usage(); return; } if (availability != winrt::UserDataAvailability::Always && availability != winrt::UserDataAvailability::AfterFirstUnlock && availability != winrt::UserDataAvailability::WhileUnlocked) { // Not a valid integer. usage(); return; } winrt::UserDataProtectionManager manager = winrt::UserDataProtectionManager::TryGetDefault(); if (!manager) { std::wcout << L"Personal Data Encryption is not enabled.\n"; return; } if (wcscmp(argv[1], L"file") == 0) { ProtectFile(manager, argv[3], availability); } else if (wcscmp(argv[1], L"folder") == 0) { ProtectFolder(manager, argv[3], availability); } else if (wcscmp(argv[1], L"memory") == 0) { ProtectMemory(manager, argv[3], availability); } else { usage(); } } int wmain(int argc, wchar_t** argv) { winrt::init_apartment(); Run(argc, argv); winrt::uninit_apartment(); return 0; }