//+--------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////////// // // Microsoft Windows // Copyright (C) Microsoft Corporation, 2000-2001. // // File: SaferEntryHashPropertyPage.cpp // // Contents: Implementation of CSaferEntryHashPropertyPage // //---------------------------------------------------------------------------- // SaferEntryHashPropertyPage.cpp : implementation file // #include "stdafx.h" #include #include "certmgr.h" #include "compdata.h" #include "SaferEntryHashPropertyPage.h" #include "SaferUtil.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif PCWSTR pcszNEWLINE = L"\x00d\x00a"; ///////////////////////////////////////////////////////////////////////////// // CSaferEntryHashPropertyPage property page CSaferEntryHashPropertyPage::CSaferEntryHashPropertyPage( CSaferEntry& rSaferEntry, LONG_PTR lNotifyHandle, LPDATAOBJECT pDataObject, bool bReadOnly, CCertMgrComponentData* pCompData, bool bIsMachine) : CHelpPropertyPage(CSaferEntryHashPropertyPage::IDD), m_rSaferEntry (rSaferEntry), m_bDirty (false), m_cbFileHash (0), m_lNotifyHandle (lNotifyHandle), m_pDataObject (pDataObject), m_bReadOnly (bReadOnly), m_bIsMachine (bIsMachine), m_hashAlgid (0), m_bFirst (true), m_pCompData (pCompData) { ::ZeroMemory (&m_nFileSize, sizeof (__int64)); ::ZeroMemory (m_rgbFileHash, SAFER_MAX_HASH_SIZE); //{{AFX_DATA_INIT(CSaferEntryHashPropertyPage) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT m_rSaferEntry.AddRef (); m_rSaferEntry.IncrementOpenPageCount (); m_rSaferEntry.GetHash (m_rgbFileHash, m_cbFileHash, m_nFileSize, m_hashAlgid); } CSaferEntryHashPropertyPage::~CSaferEntryHashPropertyPage() { if ( m_lNotifyHandle ) MMCFreeNotifyHandle (m_lNotifyHandle); m_rSaferEntry.DecrementOpenPageCount (); m_rSaferEntry.Release (); } void CSaferEntryHashPropertyPage::DoDataExchange(CDataExchange* pDX) { CHelpPropertyPage::DoDataExchange(pDX); //{{AFX_DATA_MAP(CSaferEntryHashPropertyPage) DDX_Control(pDX, IDC_HASH_ENTRY_HASHFILE_DETAILS, m_hashFileDetailsEdit); DDX_Control(pDX, IDC_HASH_ENTRY_DESCRIPTION, m_descriptionEdit); DDX_Control(pDX, IDC_HASH_ENTRY_SECURITY_LEVEL, m_securityLevelCombo); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CSaferEntryHashPropertyPage, CHelpPropertyPage) //{{AFX_MSG_MAP(CSaferEntryHashPropertyPage) ON_BN_CLICKED(IDC_HASH_ENTRY_BROWSE, OnHashEntryBrowse) ON_EN_CHANGE(IDC_HASH_ENTRY_DESCRIPTION, OnChangeHashEntryDescription) ON_CBN_SELCHANGE(IDC_HASH_ENTRY_SECURITY_LEVEL, OnSelchangeHashEntrySecurityLevel) ON_EN_CHANGE(IDC_HASH_HASHED_FILE_PATH, OnChangeHashHashedFilePath) ON_EN_SETFOCUS(IDC_HASH_HASHED_FILE_PATH, OnSetfocusHashHashedFilePath) ON_EN_CHANGE(IDC_HASH_ENTRY_HASHFILE_DETAILS, OnChangeHashEntryHashfileDetails) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CSaferEntryHashPropertyPage message handlers void CSaferEntryHashPropertyPage::DoContextHelp (HWND hWndControl) { _TRACE (1, L"Entering CSaferEntryHashPropertyPage::DoContextHelp\n"); static const DWORD help_map[] = { IDC_HASH_ENTRY_HASHFILE_DETAILS, IDH_HASH_ENTRY_APPLICATION_NAME, IDC_HASH_ENTRY_BROWSE, IDH_HASH_ENTRY_BROWSE, IDC_HASH_ENTRY_DESCRIPTION, IDH_HASH_ENTRY_DESCRIPTION, IDC_HASH_ENTRY_LAST_MODIFIED, IDH_HASH_ENTRY_LAST_MODIFIED, IDC_HASH_HASHED_FILE_PATH, IDH_HASH_HASHED_FILE_PATH, IDC_HASH_ENTRY_SECURITY_LEVEL, IDH_HASH_ENTRY_SECURITY_LEVEL, 0, 0 }; switch (::GetDlgCtrlID (hWndControl)) { case IDC_HASH_ENTRY_HASHFILE_DETAILS: case IDC_HASH_ENTRY_BROWSE: case IDC_HASH_ENTRY_DESCRIPTION: case IDC_HASH_ENTRY_LAST_MODIFIED: case IDC_HASH_HASHED_FILE_PATH: case IDC_HASH_ENTRY_SECURITY_LEVEL: if ( !::WinHelp ( hWndControl, GetF1HelpFilename(), HELP_WM_HELP, (DWORD_PTR) help_map) ) { _TRACE (0, L"WinHelp () failed: 0x%x\n", GetLastError ()); } break; default: break; } _TRACE (-1, L"Leaving CSaferEntryHashPropertyPage::DoContextHelp\n"); } BOOL CSaferEntryHashPropertyPage::OnInitDialog() { CHelpPropertyPage::OnInitDialog(); DWORD dwFlags = 0; m_rSaferEntry.GetFlags (dwFlags); ASSERT (m_pCompData); if ( m_pCompData ) { CPolicyKey policyKey (m_pCompData->m_pGPEInformation, SAFER_HKLM_REGBASE, m_bIsMachine); InitializeSecurityLevelComboBox (m_securityLevelCombo, false, m_rSaferEntry.GetLevel (), policyKey.GetKey (), m_pCompData->m_pdwSaferLevels, m_bIsMachine); m_hashFileDetailsEdit.SetWindowText (m_rSaferEntry.GetHashFriendlyName ()); m_descriptionEdit.LimitText (SAFER_MAX_DESCRIPTION_SIZE); m_descriptionEdit.SetWindowText (m_rSaferEntry.GetDescription ()); SetDlgItemText (IDC_HASH_ENTRY_LAST_MODIFIED, m_rSaferEntry.GetLongLastModified ()); SendDlgItemMessage (IDC_HASH_HASHED_FILE_PATH, EM_LIMITTEXT, 64); if ( m_bReadOnly ) { SendDlgItemMessage (IDC_HASH_HASHED_FILE_PATH, EM_SETREADONLY, TRUE); m_securityLevelCombo.EnableWindow (FALSE); GetDlgItem (IDC_HASH_ENTRY_BROWSE)->EnableWindow (FALSE); m_descriptionEdit.SendMessage (EM_SETREADONLY, TRUE); m_hashFileDetailsEdit.SendMessage (EM_SETREADONLY, TRUE); } if ( m_cbFileHash ) { // Only allow editing on the creation of a new hash SendDlgItemMessage (IDC_HASH_HASHED_FILE_PATH, EM_SETREADONLY, TRUE); FormatAndDisplayHash (); CString szText; VERIFY (szText.LoadString (IDS_HASH_TITLE)); SetDlgItemText (IDC_HASH_TITLE, szText); SetDlgItemText (IDC_HASH_INSTRUCTIONS, L""); } else SetDlgItemText (IDC_DATE_LAST_MODIFIED_LABEL, L""); } return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } typedef struct tagVERHEAD { WORD wTotLen; WORD wValLen; WORD wType; /* always 0 */ WCHAR szKey[(sizeof("VS_VERSION_INFO")+3)&~03]; VS_FIXEDFILEINFO vsf; } VERHEAD ; /* * [alanau] * * MyGetFileVersionInfo: Maps a file directly without using LoadLibrary. This ensures * that the right version of the file is examined without regard to where the loaded image * is. Since this is a local function, it allocates the memory which is freed by the caller. * This makes it slightly more efficient than a GetFileVersionInfoSize/GetFileVersionInfo pair. */ BOOL CSaferEntryHashPropertyPage::MyGetFileVersionInfo(LPTSTR lpszFilename, LPVOID *lpVersionInfo) { // VS_FIXEDFILEINFO *pvsFFI = NULL; // UINT uiBytes = 0; HINSTANCE hinst = 0; HRSRC hVerRes = 0; HANDLE FileHandle = NULL; HANDLE MappingHandle = NULL; LPVOID DllBase = NULL; VERHEAD *pVerHead = 0; BOOL bResult = FALSE; DWORD dwHandle = 0; DWORD dwLength = 0; if (!lpVersionInfo) return FALSE; *lpVersionInfo = NULL; FileHandle = CreateFile( lpszFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); if (FileHandle == INVALID_HANDLE_VALUE) goto Cleanup; MappingHandle = CreateFileMapping( FileHandle, NULL, PAGE_READONLY, 0, 0, NULL ); if (MappingHandle == NULL) goto Cleanup; DllBase = MapViewOfFileEx( MappingHandle, FILE_MAP_READ, 0, 0, 0, NULL ); if (DllBase == NULL) goto Cleanup; hinst = (HMODULE)((ULONG_PTR)DllBase | 0x00000001); __try { hVerRes = FindResource(hinst, MAKEINTRESOURCE(VS_VERSION_INFO), VS_FILE_INFO); if (hVerRes == NULL) { // Probably a 16-bit file. Fall back to system APIs. dwLength = GetFileVersionInfoSize(lpszFilename, &dwHandle); if( !dwLength ) { if(!GetLastError()) SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND); __leave; } *lpVersionInfo = ::LocalAlloc (LPTR, dwLength); if ( !(*lpVersionInfo) ) __leave; if(!GetFileVersionInfo(lpszFilename, 0, dwLength, *lpVersionInfo)) __leave; bResult = TRUE; __leave; } pVerHead = (VERHEAD*)LoadResource(hinst, hVerRes); if (pVerHead == NULL) __leave; *lpVersionInfo = ::LocalAlloc (LPTR, pVerHead->wTotLen + pVerHead->wTotLen/2); if (*lpVersionInfo == NULL) __leave; memcpy(*lpVersionInfo, (PVOID)pVerHead, pVerHead->wTotLen); bResult = TRUE; } __except (EXCEPTION_EXECUTE_HANDLER) { } Cleanup: if (FileHandle) CloseHandle(FileHandle); if (MappingHandle) CloseHandle(MappingHandle); if (DllBase) UnmapViewOfFile(DllBase); if (*lpVersionInfo && bResult == FALSE) ::LocalFree (*lpVersionInfo); return bResult; } /////////////////////////////////////////////////////////////////////////////// // // Method: OnHashEntryBrowse // // Purpose: Allow the user to browse for a file, then create a hash and an // output string for use as the friendly name, using the following // rules: // // If either the product name or description information is found in // the version resource, provide the following (in order): // // Description // Product name // Company name // File name // Fixed file version // // Details: // 1) Use the fixed file version, since that is what is shown in the // Windows Explorer properties. // 2) Prefer the long file name to the 8.3 name. // 3) Delimit the fields with '\n'. // 4) If the field is missing, don't output the field or the delimiter // 5) Instead of displaying the file version on a new line, display // it after the file name in parens, as in "Filename (1.0.0.0)" // 6) Since we are limited to 256 TCHARs, we have to accomodate long // text. First, format the text as described above to determine // its length. If it is too long, truncate one field at a time in // the following order: Company name, Description, Product name. // To truncate a field, set it to a maximum of 60 TCHARs, then // append a "...\n" to visually indicate that the field was // truncated. Lastly, if the text is still to long, use the 8.3 // file name instead of the long filename. // // If neither the product name nor description information is found, // provide the following (in order): // // File name // File size // File last modified date // // Details: // 1) If the file size is < 1 KB, display the number in bytes, as in // "123 bytes". If the file size is >= 1 KB, display in KB, as in // "123 KB". Of course, 1 KB is 1024 bytes. Note that the older // style format "123K" is no longer used in Windows. // 2) For the last modified date, use the short format version in the // user's current locale. // 3) Delimit the fields with '\n'. // 4) If the field is missing, don't output the field or the delimiter // /////////////////////////////////////////////////////////////////////////////// void CSaferEntryHashPropertyPage::OnHashEntryBrowse() { CString szFileFilter; VERIFY (szFileFilter.LoadString (IDS_SAFER_PATH_ENTRY_FILE_FILTER)); // replace "|" with 0; const size_t nFilterLen = wcslen (szFileFilter) + 1; PWSTR pszFileFilter = new WCHAR [nFilterLen]; if ( pszFileFilter ) { wcscpy (pszFileFilter, szFileFilter); for (int nIndex = 0; nIndex < nFilterLen; nIndex++) { if ( L'|' == pszFileFilter[nIndex] ) pszFileFilter[nIndex] = 0; } WCHAR szFile[MAX_PATH]; ::ZeroMemory (szFile, MAX_PATH * sizeof (WCHAR)); wcscpy (szFile, m_szLastOpenedFile); OPENFILENAME ofn; ::ZeroMemory (&ofn, sizeof (OPENFILENAME)); ofn.lStructSize = sizeof (OPENFILENAME); ofn.hwndOwner = m_hWnd; ofn.lpstrFilter = (PCWSTR) pszFileFilter; ofn.lpstrFile = szFile; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_DONTADDTORECENT | OFN_FORCESHOWHIDDEN | OFN_HIDEREADONLY; CThemeContextActivator activator; BOOL bResult = ::GetOpenFileName (&ofn); if ( bResult ) { m_szLastOpenedFile = ofn.lpstrFile; HANDLE hFile = ::CreateFile( ofn.lpstrFile, // file name GENERIC_READ, // access mode FILE_SHARE_READ, // share mode 0, // SD OPEN_EXISTING, // how to create FILE_ATTRIBUTE_NORMAL, // file attributes 0 ); // handle to template file if ( INVALID_HANDLE_VALUE != hFile ) { bResult = GetFileSizeEx( hFile, // handle to file (PLARGE_INTEGER) &m_nFileSize); // file size if ( !bResult ) { DWORD dwErr = GetLastError (); CloseHandle (hFile); _TRACE (0, L"GetFileSizeEx () failed: 0x%x\n", dwErr); CString text; CString caption; VERIFY (caption.LoadString (IDS_SAFER_WINDOWS_NODE_NAME)); text.FormatMessage (IDS_CANNOT_GET_FILESIZE, ofn.lpstrFile, GetSystemMessage (dwErr)); MessageBox (text, caption, MB_OK); return; } if ( 0 == m_nFileSize ) { CString text; CString caption; VERIFY (caption.LoadString (IDS_SAFER_WINDOWS_NODE_NAME)); text.FormatMessage (IDS_ZERO_BYTE_FILE_CANNOT_HASH, ofn.lpstrFile); MessageBox (text, caption, MB_OK); return; } FILETIME ftLastModified; bResult = ::GetFileTime (hFile, // handle to file 0, // creation time 0, // last access time &ftLastModified); // last write time ::ZeroMemory (m_rgbFileHash, SAFER_MAX_HASH_SIZE); HRESULT hr = GetSignedFileHash (ofn.lpstrFile, m_rgbFileHash, &m_cbFileHash, &m_hashAlgid); if ( FAILED (hr) ) { m_hashAlgid = 0; hr = ComputeMD5Hash (hFile, m_rgbFileHash, m_cbFileHash); if ( SUCCEEDED (hr) ) { if ( SHA1_HASH_LEN == m_cbFileHash ) m_hashAlgid = CALG_SHA; else if ( MD5_HASH_LEN == m_cbFileHash ) m_hashAlgid = CALG_MD5; else { ASSERT (0); } } } VERIFY (CloseHandle (hFile)); hFile = 0; if ( SUCCEEDED (hr) ) { FormatAndDisplayHash (); PBYTE pData = 0; bResult = MyGetFileVersionInfo (ofn.lpstrFile, (LPVOID*) &pData); if ( bResult ) { CString infoString = BuildHashFileInfoString (pData); m_hashFileDetailsEdit.SetWindowText (infoString); m_bDirty = true; SetModified (); } else { CString infoString (wcsrchr(ofn.lpstrFile, L'\\') + 1); CString szDate; infoString += pcszNEWLINE; WCHAR szBuffer[32]; CString szText; if ( m_nFileSize < 1024 ) { wsprintf (szBuffer, L"%u", m_nFileSize); infoString += szBuffer; VERIFY (szText.LoadString (IDS_BYTES)); infoString += L" "; infoString += szText; } else { __int64 nFileSize = m_nFileSize; nFileSize += 1024; // this causes us to round up nFileSize /= 1024; wsprintf (szBuffer, L"%u ", nFileSize); infoString += szBuffer; VERIFY (szText.LoadString (IDS_KB)); infoString += L" "; infoString += szText; } hr = FormatDate (ftLastModified, szDate, DATE_SHORTDATE, true); if ( SUCCEEDED (hr) ) { infoString += pcszNEWLINE; infoString += szDate; } m_hashFileDetailsEdit.SetWindowText (infoString); m_bDirty = true; SetModified (); } ::LocalFree (pData); } else { CString text; CString caption; VERIFY (caption.LoadString (IDS_SAFER_WINDOWS_NODE_NAME)); text.FormatMessage (IDS_CANNOT_HASH_FILE, ofn.lpstrFile, GetSystemMessage (hr)); MessageBox (text, caption, MB_OK); } } else { DWORD dwErr = GetLastError (); _TRACE (0, L"CreateFile (%s, OPEN_EXISTING) failed: 0x%x\n", ofn.lpstrFile, dwErr); CString text; CString caption; VERIFY (caption.LoadString (IDS_SAFER_WINDOWS_NODE_NAME)); text.FormatMessage (IDS_FILE_CANNOT_BE_READ, ofn.lpstrFile, GetSystemMessage (dwErr)); MessageBox (text, caption, MB_OK); } } delete [] pszFileFilter; } } /***************************************************************************\ * * BuildHashFileInfoString() * * Given a file name, GetVersion retrieves the version * information from the specified file. * * \***************************************************************************/ const PWSTR VERSION_INFO_KEY_ROOT = L"\\StringFileInfo\\"; CString CSaferEntryHashPropertyPage::BuildHashFileInfoString (PVOID pData) { CString szInfoString; PVOID lpInfo = 0; UINT cch = 0; CString key; WCHAR szBuffer[10]; CString keyBase; wsprintf (szBuffer, L"%04X", GetUserDefaultLangID ()); wcscat (szBuffer, L"04B0"); keyBase = VERSION_INFO_KEY_ROOT; keyBase += szBuffer; keyBase += L"\\"; CString productName; CString description; CString companyName; CString fileName; CString fileVersion; key = keyBase + L"ProductName"; if ( VerQueryValue (pData, const_cast ((PCWSTR) key), &lpInfo, &cch) ) { productName = (PWSTR) lpInfo; } key = keyBase + L"FileDescription"; if ( VerQueryValue (pData, const_cast ((PCWSTR) key), &lpInfo, &cch) ) { description = (PWSTR) lpInfo; } key = keyBase + L"CompanyName"; if ( VerQueryValue (pData, const_cast ((PCWSTR) key), &lpInfo, &cch) ) { companyName = (PWSTR) lpInfo; } key = keyBase + L"OriginalFilename"; if ( VerQueryValue (pData, const_cast ((PCWSTR) key), &lpInfo, &cch) ) { fileName = (PWSTR) lpInfo; } // Get Fixedlength fileInfo VS_FIXEDFILEINFO *pFixedFileInfo = 0; if ( VerQueryValue (pData, L"\\", (PVOID*) &pFixedFileInfo, &cch) ) { WCHAR szFileVer[32]; wsprintf(szFileVer, L"%u.%u.%u.%u", HIWORD(pFixedFileInfo->dwFileVersionMS), LOWORD(pFixedFileInfo->dwFileVersionMS), HIWORD(pFixedFileInfo->dwFileVersionLS), LOWORD(pFixedFileInfo->dwFileVersionLS)); fileVersion = szFileVer; } int nLen = 0; do { szInfoString = ConcatStrings (productName, description, companyName, fileName, fileVersion); nLen = szInfoString.GetLength (); if ( nLen >= SAFER_MAX_FRIENDLYNAME_SIZE ) { if ( CheckLengthAndTruncateToken (companyName) ) continue; if ( CheckLengthAndTruncateToken (description) ) continue; if ( CheckLengthAndTruncateToken (productName) ) continue; szInfoString.SetAt (SAFER_MAX_FRIENDLYNAME_SIZE-4, 0); szInfoString += L"..."; } } while (nLen >= SAFER_MAX_FRIENDLYNAME_SIZE); return szInfoString; } bool CSaferEntryHashPropertyPage::CheckLengthAndTruncateToken (CString& token) { bool bResult = false; const int nMAX_ITEM_LEN = 60; int nItemLen = token.GetLength (); if ( nItemLen > nMAX_ITEM_LEN ) { token.SetAt (nMAX_ITEM_LEN-5, 0); token += L"..."; token += pcszNEWLINE; bResult = true; } return bResult; } CString CSaferEntryHashPropertyPage::ConcatStrings ( const CString& productName, const CString& description, const CString& companyName, const CString& fileName, const CString& fileVersion) { CString szInfoString; if ( !description.IsEmpty () ) szInfoString += description + pcszNEWLINE; if ( !productName.IsEmpty () ) szInfoString += productName + pcszNEWLINE; if ( !companyName.IsEmpty () ) szInfoString += companyName + pcszNEWLINE; if ( !fileName.IsEmpty () ) szInfoString += fileName; if ( !fileVersion.IsEmpty () ) { szInfoString += L" ("; szInfoString += fileVersion + L")";; } return szInfoString; } BOOL CSaferEntryHashPropertyPage::OnApply() { CString szText; CThemeContextActivator activator; GetDlgItemText (IDC_HASH_HASHED_FILE_PATH, szText); if ( szText.IsEmpty () ) { CString szCaption; VERIFY (szCaption.LoadString (IDS_SAFER_WINDOWS_NODE_NAME)); VERIFY (szText.LoadString (IDS_USER_MUST_ENTER_HASH)); MessageBox (szText, szCaption, MB_OK); GetDlgItem (IDC_HASH_HASHED_FILE_PATH)->SetFocus (); return FALSE; } if ( !m_bReadOnly && m_bDirty ) { if ( !ConvertStringToHash ((PCWSTR) szText) ) { GetDlgItem (IDC_HASH_HASHED_FILE_PATH)->SetFocus (); return FALSE; } // Get image size and hash type bool bBadFormat = false; int nFirstColon = szText.Find (L":", 0); if ( -1 != nFirstColon ) { int nSecondColon = szText.Find (L":", nFirstColon+1); if ( -1 != nSecondColon ) { CString szImageSize = szText.Mid (nFirstColon+1, nSecondColon - (nFirstColon + 1)); CString szHashType = szText.Right (((int) wcslen (szText)) - (nSecondColon + 1)); m_nFileSize = wcstol (szImageSize, 0, 10); m_hashAlgid = wcstol (szHashType, 0, 10); } else bBadFormat = true; } else bBadFormat = true; if ( bBadFormat ) { CString caption; VERIFY (caption.LoadString (IDS_SAFER_WINDOWS_NODE_NAME)); VERIFY (szText.LoadString (IDS_HASH_STRING_BAD_FORMAT)); MessageBox (szText, caption, MB_OK); return FALSE; } if ( !m_cbFileHash ) { CString caption; VERIFY (caption.LoadString (IDS_SAFER_WINDOWS_NODE_NAME)); VERIFY (szText.LoadString (IDS_NO_APPLICATION_SELECTED)); MessageBox (szText, caption, MB_OK); GetDlgItem (IDC_HASH_ENTRY_BROWSE)->SetFocus (); return FALSE; } if ( m_bDirty ) { // Set the level int nCurSel = m_securityLevelCombo.GetCurSel (); ASSERT (CB_ERR != nCurSel); m_rSaferEntry.SetLevel ((DWORD) m_securityLevelCombo.GetItemData (nCurSel)); // Set description m_descriptionEdit.GetWindowText (szText); m_rSaferEntry.SetDescription (szText); // Set friendly name m_hashFileDetailsEdit.GetWindowText (szText); m_rSaferEntry.SetHashFriendlyName (szText); // Get and save flags DWORD dwFlags = 0; m_rSaferEntry.SetFlags (dwFlags); m_rSaferEntry.SetHash (m_rgbFileHash, m_cbFileHash, m_nFileSize, m_hashAlgid); HRESULT hr = m_rSaferEntry.Save (); if ( SUCCEEDED (hr) ) { if ( m_lNotifyHandle ) MMCPropertyChangeNotify ( m_lNotifyHandle, // handle to a notification (LPARAM) m_pDataObject); // unique identifier m_bDirty = false; } else { CString caption; VERIFY (caption.LoadString (IDS_SAFER_WINDOWS_NODE_NAME)); if ( HRESULT_FROM_WIN32 (ERROR_INVALID_PARAMETER) != hr ) szText.FormatMessage (IDS_ERROR_SAVING_ENTRY, GetSystemMessage (hr)); else VERIFY (szText.LoadString (IDS_HASH_STRING_BAD_FORMAT)); MessageBox (szText, caption, MB_OK); return FALSE; } } } return CHelpPropertyPage::OnApply(); } void CSaferEntryHashPropertyPage::OnChangeHashEntryDescription() { m_bDirty = true; SetModified (); } void CSaferEntryHashPropertyPage::OnSelchangeHashEntrySecurityLevel() { m_bDirty = true; SetModified (); } void CSaferEntryHashPropertyPage::OnChangeHashHashedFilePath() { m_bDirty = true; SetModified (); } bool CSaferEntryHashPropertyPage::FormatMemBufToString(PWSTR *ppString, PBYTE pbData, DWORD cbData) { const WCHAR RgwchHex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; DWORD i = 0; PBYTE pb; *ppString = (LPWSTR) LocalAlloc (LPTR, ((cbData * 3) * sizeof(WCHAR))); if ( !*ppString ) { return false; } // // copy to the buffer // pb = pbData; while (pb <= &(pbData[cbData-1])) { (*ppString)[i++] = RgwchHex[(*pb & 0xf0) >> 4]; (*ppString)[i++] = RgwchHex[*pb & 0x0f]; pb++; } (*ppString)[i] = 0; return true; } bool CSaferEntryHashPropertyPage::ConvertStringToHash (PCWSTR pszString) { _TRACE (1, L"Entering CSaferEntryHashPropertyPage::ConvertStringToHash (%s)\n", pszString); bool bRetVal = true; BYTE rgbFileHash[SAFER_MAX_HASH_SIZE]; ::ZeroMemory (rgbFileHash, SAFER_MAX_HASH_SIZE); DWORD cbFileHash = 0; DWORD dwNumHashChars = 0; bool bFirst = true; bool bEndOfHash = false; CThemeContextActivator activator; for (int nIndex = 0; !bEndOfHash && pszString[nIndex] && bRetVal; nIndex++) { if ( cbFileHash >= SAFER_MAX_HASH_SIZE ) { CString caption; CString text; VERIFY (caption.LoadString (IDS_SAFER_WINDOWS_NODE_NAME)); text.FormatMessage (IDS_HASH_STRING_TOO_LONG, SAFER_MAX_HASH_SIZE, SAFER_MAX_HASH_SIZE/4); _TRACE (0, L"%s", (PCWSTR) text); VERIFY (text.LoadString (IDS_HASH_STRING_BAD_FORMAT)); MessageBox (text, caption, MB_ICONWARNING | MB_OK); bRetVal = false; break; } dwNumHashChars++; switch (pszString[nIndex]) { case L'0': bFirst = !bFirst; break; case L'1': if ( bFirst ) rgbFileHash[cbFileHash] |= 0x10; else rgbFileHash[cbFileHash] |= 0x01; bFirst = !bFirst; break; case L'2': if ( bFirst ) rgbFileHash[cbFileHash] |= 0x20; else rgbFileHash[cbFileHash] |= 0x02; bFirst = !bFirst; break; case L'3': if ( bFirst ) rgbFileHash[cbFileHash] |= 0x30; else rgbFileHash[cbFileHash] |= 0x03; bFirst = !bFirst; break; case L'4': if ( bFirst ) rgbFileHash[cbFileHash] |= 0x40; else rgbFileHash[cbFileHash] |= 0x04; bFirst = !bFirst; break; case L'5': if ( bFirst ) rgbFileHash[cbFileHash] |= 0x50; else rgbFileHash[cbFileHash] |= 0x05; bFirst = !bFirst; break; case L'6': if ( bFirst ) rgbFileHash[cbFileHash] |= 0x60; else rgbFileHash[cbFileHash] |= 0x06; bFirst = !bFirst; break; case L'7': if ( bFirst ) rgbFileHash[cbFileHash] |= 0x70; else rgbFileHash[cbFileHash] |= 0x07; bFirst = !bFirst; break; case L'8': if ( bFirst ) rgbFileHash[cbFileHash] |= 0x80; else rgbFileHash[cbFileHash] |= 0x08; bFirst = !bFirst; break; case L'9': if ( bFirst ) rgbFileHash[cbFileHash] |= 0x90; else rgbFileHash[cbFileHash] |= 0x09; bFirst = !bFirst; break; case L'a': case L'A': if ( bFirst ) rgbFileHash[cbFileHash] |= 0xA0; else rgbFileHash[cbFileHash] |= 0x0A; bFirst = !bFirst; break; case L'b': case L'B': if ( bFirst ) rgbFileHash[cbFileHash] |= 0xB0; else rgbFileHash[cbFileHash] |= 0x0B; bFirst = !bFirst; break; case L'c': case L'C': if ( bFirst ) rgbFileHash[cbFileHash] |= 0xC0; else rgbFileHash[cbFileHash] |= 0x0C; bFirst = !bFirst; break; case L'd': case L'D': if ( bFirst ) rgbFileHash[cbFileHash] |= 0xD0; else rgbFileHash[cbFileHash] |= 0x0D; bFirst = !bFirst; break; case L'e': case L'E': if ( bFirst ) rgbFileHash[cbFileHash] |= 0xE0; else rgbFileHash[cbFileHash] |= 0x0E; bFirst = !bFirst; break; case L'f': case L'F': if ( bFirst ) rgbFileHash[cbFileHash] |= 0xF0; else rgbFileHash[cbFileHash] |= 0x0F; bFirst = !bFirst; break; case L':': // end of hash bEndOfHash = true; bFirst = !bFirst; dwNumHashChars--; // ':' already counted, subtract it break; default: bRetVal = false; { CString caption; CString text; WCHAR szChar[2]; szChar[0] = pszString[nIndex]; szChar[1] = 0; VERIFY (caption.LoadString (IDS_SAFER_WINDOWS_NODE_NAME)); text.FormatMessage (IDS_HASH_STRING_INVALID_CHAR, szChar); _TRACE (0, L"%s", (PCWSTR) text); VERIFY (text.LoadString (IDS_HASH_STRING_BAD_FORMAT)); MessageBox (text, caption, MB_ICONWARNING | MB_OK); } break; } if ( bFirst ) cbFileHash++; } if ( bRetVal ) { // 2 characters map to 1 each byte in the hash if ( MD5_HASH_LEN != dwNumHashChars/2 && SHA1_HASH_LEN != dwNumHashChars/2 ) { CString caption; CString text; VERIFY (caption.LoadString (IDS_SAFER_WINDOWS_NODE_NAME)); VERIFY (text.LoadString (IDS_HASH_INVALID_LENGTH)); _TRACE (0, L"%s", (PCWSTR) text); VERIFY (text.LoadString (IDS_HASH_STRING_BAD_FORMAT)); MessageBox (text, caption, MB_ICONWARNING | MB_OK); bRetVal = false; } else { m_cbFileHash = cbFileHash; memcpy (m_rgbFileHash, rgbFileHash, SAFER_MAX_HASH_SIZE); } } _TRACE (-1, L"Leaving CSaferEntryHashPropertyPage::ConvertStringToHash (): %s\n", bRetVal ? L"true" : L"false"); return bRetVal; } void CSaferEntryHashPropertyPage::OnSetfocusHashHashedFilePath() { if ( m_bFirst ) { if ( true == m_bReadOnly ) SendDlgItemMessage (IDC_HASH_HASHED_FILE_PATH, EM_SETSEL, (WPARAM) 0, 0); m_bFirst = false; } } void CSaferEntryHashPropertyPage::FormatAndDisplayHash () { PWSTR pwszText = 0; if ( FormatMemBufToString (&pwszText, m_rgbFileHash, m_cbFileHash) ) { WCHAR szAlgID[10]; _ltow (m_hashAlgid, szAlgID, 10); PWSTR pszFormattedText = new WCHAR[wcslen (pwszText) + 50]; if ( pszFormattedText ) { wsprintf (pszFormattedText, L"%s:%ld:", pwszText, m_nFileSize); wcscat (pszFormattedText, szAlgID); SetDlgItemText (IDC_HASH_HASHED_FILE_PATH, pszFormattedText); delete [] pszFormattedText; } LocalFree (pwszText); } } void CSaferEntryHashPropertyPage::OnChangeHashEntryHashfileDetails() { SetModified (); m_bDirty = true; }