引言:
在开发一款对外发布的软件程序时,难免要用到配置文件,而其中某些数据开发者并不期望用户获知或是修改,通常会对一些配置文件进行加密。一般是用一个批量的加密工具,统一对配置文件进行加密。
考虑到加密、解密的效率及对安全性的需求,选择了最常用的XOR算法,以下是加密工具的源代码:(windows环境下基于XOR算法,带有图形界面的文件批量加密工具)
源代码:
由于XOR算法是直接可逆的,故源代码中略去了部分代码。
EncryptXML.h:
#pragma once #include <vector> #include <atlframe.h> #include <atlwin.h> #include <ShlObj.h> #include "Resource.h" using namespace std; struct encrypt_context { unsigned char mask[1024]; unsigned int mask_len; }; class CEncryptXML : public CDialogImpl<CEncryptXML>, public CUpdateUI<CEncryptXML>, public CMessageFilter, public CIdleHandler { public: enum { IDC = IDD_DIALOG1 }; BOOL PreTranslateMessgae(MSG* pMsg) { return CWindow::IsDialogMessage(pMsg); } BOOL OnIdle() { return FALSE; } BEGIN_UPDATE_UI_MAP(CEncryptXML) END_UPDATE_UI_MAP() BEGIN_MSG_MAP(CEncryptXML) MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) COMMAND_HANDLER(IDC_BUTTON1, BN_CLICKED, OnBnBrowse) COMMAND_HANDLER(IDOK, BN_CLICKED, OnBnOk) COMMAND_HANDLER(IDCANCEL, BN_CLICKED, OnBnCancel) END_MSG_MAP() public: //UI code LRESULT OnInitDialog(UINT, WPARAM, LPRAM, BOOL&); LRESULT OnBnBrowse(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); LRESULT OnBnOk(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); LRESULT OnBnCancel(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); int ValidPath(const std::wstring& strPath); //encrypt code. void CollectFilesByDirectory(const TCHAR* firstroot, const TCHAR* root, const TCHAR* outdir); BOOL CollectFilesBySingleFile(const TCHAR* fileName, std::wstring& dest); void CollectDeleteDirectory(const TCHAR* firstroot, const TCHAR* root, const TCHAR* outdir); void encryptdata(const encrypt_context& ctx, unsigned char* data, size_t pos, size_t len); BOOL encryptfile(encrypt_context& ectx, const TCHAR* src_file, const TCHAR* dest_file); BOOL EncryptXML(const TCHAR* fileName, const TCHAR* destPath); void DoEncrypt(const TCHAR* fileName); private: std::vector <std::wstring> arSourceFileName; ///< 源文件列表 std::vector <std::wstring> arDestFileNamep; ///< 临时文件列表 std::vector <std::wstring> arEncryptFailedFileName; ///< 加密失败文件列表 std::vector <std::wstring> arDirectoryNeedToBeDeleted; ///< 待删除文件夹列表 };
EncryptXML.cpp:
#include "stdafx.h" #include "EncryptXML.h" #include "Resource.h" #include "..\TCommonUtiliLib\common.h" #include <WinBase.h> #include <iostream> #include <Windows.h> CAppModule _Module; int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) { if (uMsg == BFFM_INITIALIZED) { SendMessage(hwnd, BFFM_SETSELECTION, 1, lpData); return 0; } return 0; } std::wstring BrowseForInstallDestination(HWND m_hWnd, const std::wstring& initdir) { BROWSEINFO bi; bi.hwndOwner = m_hWnd; bi.pidlRoot = NULL; bi.pszDisplayName = NULL; std::wstring title = L"请选择要加密的文件或文件夹:"; bi.lpszTitle = title.c_str(); //bi.ulFlags = 0; bi.ulFlags = BIF_BROWSEINCLUDEFILES; ///< 最初的版本仅支持选定文件夹,后来需要对单个文件进行加密 bi.lpfn = BrowseCallbackProc; bi.lParam = (LPARAM)initdir.c_str(); bi.Image = 0; TCHAR installPath[1024]; PIDLIST_ABSOLUTE ret = ::SHBrowseForFolder(&bi); if (ret == NULL) { ZeroMemory(installPath, sizeof installPath); } else { ::SHGetPathFromIDList(ret, installPath); } return installPath; } void CEncryptXML::CollectFilesByDirectory(const TCHAR* firstroot, const TCHAR* root , const TCHAR* outdir) { WIN32_FIND_DATA fd; THCAR fullname[MAX_PATH + 1]; size_t offset = ::wcslen(firstroot); ::_stprintf_s(fullname, MAX_PATH + 1, L"%s\\%s", root, L"*.*"); HANDLE hf = ::FindFirstFile(fullname, &fd); BOOL b = hf != INVALID_HANDLE_VALUE; while(b) { ::_stprintf_s(fullname, MAX_PATH + 1, L"%s\\%s", root, fd.cFileName); if (!(wcscmp(fd.cFileName, L".") == 0 || wcscmp(fd.cFileName, L"..") == 0)) { if(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { CollectFilesByDirectory(firstroot, fullname, outdir); } else { TCHAR dummy[1024]; TCHAR ext[1024]; TCHAR output_filename[1024]; ::_stprintf_s(output_filename, 1024, L"%s%s", outdir, fullname + offset); ::_wsplitpath_s(output_filename, dummy, 1024, dummy, 1024, dummy, 1024, ext, 1024); ///< 过滤后缀名,只对.xml文件加密 if(wcscmp(ext, L".xml") == 0) { arSourceFileName.push_back(fullname); arDestFileName.push_back(output_filename); } } } b = ::FindNextFile(hf, &fd); } ::FindClose(hf); } void CEncryptXML::encryptdata(const encrypt_context& ctx, unsigned char* data, size_t pos, size_t len) { size_t i = 0; while(i < len) { *data++ ^= /*省略计算方法*/ i++; } } BOOL CEncryptXML::encryptfile(encrypt_context& ectx, const TCHAR* src_file, const TCHAR* dest_file) { TCreatePath(dest_file); FILE* pf; FILE* pf2; errno_t err = ::_wfopen_s(&pf, src_file, L"rb"); if(err != 0) { return FALSE; } err = ::_wfopen_s(&pf2, dest_file, L"wb"); if(err != 0) { fclose(pf); return FALSE; } size_t pos = 0; unsigned char buffer[4096]; while(!feof(pf)) { size_t readed = ::fread_s(buffer, 4096, 1, 4096, pf); encryptdata(ectx, buffer, pos, readed); if(fwrite(buffer, 1, readed, pf2) != readed) { fclose(pf); fclose(pf2); return FALSE; } pos += readed; } fclose(pf); fclose(pf2); return TRUE; } BOOL CEncryptXML::EncryptXML(const TCHAR* fileName, const TCHAR* destPath) { encrypt_context enc_ctx; __int64 ilen = TGetFileSize(fileName); if(ilen <= 0) return FALSE; size_t len = (size_t)ilen; enc_ctx.mask_len = 1024; enc_ctx.mask[0] =/*省略计算方法*/ for (int i = 1; i < 1024; ++i) enc_ctx.mask[i] = /*省略计算方法*/ return encryptfile(enc_ctx, fileName, destPath); } LRESULT CEncryptXML::OnInitDialog(UINT, WPARAM, LPARAM, BOOL&) { // center the dialog on the screen CenterWindow(); // register object for message filtering and idle updates CMessageLoop* pLoop = _Module.GetMessageLoop(); ATLASSERT(pLoop != NULL); pLoop->AddMessageFilter(this); pLoop->AddIdleHandler(this); return TRUE; } int CEncryptXML::ValidPath(const std::wstring& strPath) { std::wstring s = strPath; if(s.empty()) return 0; if(s.find_last_of(L"\\") != s.length() - 1) s += L"\\"; int ret = TCreatePath2(s.c_str()); //xml files should be in a exist directory. if(ret == ERROR_FILE_EXISTS || ret == ERROR_ALREADY_EXISTS) return 1; return 0; } LRESULT CEncryptXML::OnBnBrowse(WORD, WORD, HWND, BOOL&) { TCHAR intdir[1024]; ZeroMemory(intdir, sizeof intdir); if(FALSE == SHGetSpecialFolderPath(m_hWnd, intdir, CSIDL_PROGRAM_FILES, TRUE)) { wcscpy_s<1024>(intdir, L"D:\\"); } std::wstring result = BrowseForInstallDestination(m_hWnd, intdir); if(!result.empty()) { TFixPath(result); CEDIT edit = GetDlgItem(IDC_EDIT1); edit.SetWindowText(result.c_str()); } return 0; } LRESULT CEncryptXML::OnBnOk(WORD, WORD, HWND, BOOL&) { TCHAR dir[1024]; ZeroMemory(dir, sizeof dir); CEdit edit = GetDlgItem(IDC_EDIT1); edit.GetWindowtext(dir, 1022); int ret = ValidPath(std::wstring(dir)); if(ret == 0) { MessageBox(L"选择的路径有误!", L"提示", MB_OK); } else { DoEncrypt(dir); } return 0; } LRESULT CEncryptXML::OnBnCancel(WORD, WORD, HWND, BOOL&) { DestoryWindow(); PostQuitMessage(0); return 0; } void CEncryptXML::DoEncrypt(const TCHAR* fileName) { std::wstring dest = L""; std::wstring errorStr = L""; ///< 选择的文件夹 if (PathIsDirectory(fileName)) { dest = std::wstring(fileName) + L"\\temp"; CollectFilesByDirectory(fileName, fileName, dest.c_str()); } ///< 选的文件 else { if (!CollectFilesBySingleFile(fileName, dest)) return; } for (size_t i = 0; i < arSourceFileName.size(); ++i) { if (!EncryptXML(arSourceFileName[i].c_str(), arDestFileName[i].c_str())) { arEncryptFailedFileName.push_back(arSourceFileName[i]); ::DeleteFile(arDestFileName[i].c_str()); continue; } ///< 文件为只读时,CopyFile会失败 if (!::CopyFile(arDestFileName[i].c_str(), arSourceFileName[i].c_str(), FALSE)) { arEncryptFailedFileName.push_back(arSourceFileName[i]); ::DeleteFile(arDestFileName[i].c_str()); continue; } if (!::DeleteFile(arDestFileName[i].c_str())) { arEncryptFailedFileName.push_back(arSourceFileName[i]); continue; } } CollectDeleteDirectory(dest.c_str(), dest.c_str(), dest.c_str()); for (size_t i = 0; i <arDirectoryNeedToBeDeleted.size(); ++i) { if (!::RemoveDirectory(arDirectoryNeedToBeDeleted[i].c_str())) { errStr = arDirectoryNeedToBeDeleted[i] + L"删除失败!"; MessageBox(errorStr.c_str(), L"提示", MB_OK); } } if (!::RemoveDirectory(dest.c_str())) { errorStr = dest + L"删除失败!"; MessageBox(errorStr.c_str(), L"提示", MB_OK); } if (arEncryptFailedFileName.empty()) { MessageBox(L"加密成功!", L"提示", MB_OK); } else { std::wstring errorFileName = L""; for (size_t i = 0; i < arEncryptFailedFileName.size(); ++i) { errorFileName += arEncryptFailedFileName[i]; errorFileName += '\n'; } errorFileName += L"加密失败!"; MessageBox(errorFileName.c_str(), L"提示", MB_OK); } DestroyWindow(); PostQuitMessage(0); } BOOL CEncryptXML::CollectFilesBySingleFile(const TCHAR* fileName, std::wstring& dest) { std::wstring strFileName = fileName; std::wstring::size_type pos; std::wstring tempDest; TCHAR dummy[1024]; TCHAR ext[1024]; pos = strFileName.find_last_of(L"\\"); if (pos == std::wstring::npos) { MessageBox(L"解析文件路径失败!", L"提示", MB_OK); return FALSE; } tempDest = strFileName.substr(0, pos); dest = tempDest + L"\\temp"; size_t offset = ::wcslen(tempDest.c_str()); TCHAR output_filename[1024]; ::_stprintf_s(output_filename, 1024, L"%s%s", dest.c_str(), fileName + offset); ::_wsplitpath_s(output_filename, dummy, 1024, dummy, 1024, dummy, 1024, ext, 1024); ///< 过滤后缀名,只对.xml文件加密 if (wcscmp(ext, L".xml") != 0) { MessageBox(L"选择的文件不是xml文件,请重新选择。", L"提示", MB_OK); return FALSE; } else { arSourceFileName.push_back(fileName); arDestFileName.push_back(output_filename); } return TRUE; } void CEncryptXML::CollectDeleteDirectory(const TCHAR* firstroot, const TCHAR* root, const TCHAR* outdir) { WIN32_FIND_DATA fd; TCHAR fullname[MAX_PATH + 1]; size_t offset = ::wcslen(firstroot); ::_stprintf_s(fullname, MAX_PATH + 1, L"%s\\%s", root, L"*.*"); HANDLE hf = ::FindFirstFile(fullname, &fd); BOOL b = hf != INVALID_HANDLE_VALUE; while(b) { ::_stprintf_s(fullname, MAX_PATH + 1, L"%s\\%s", root, fd.cFileName); if (!(wcscmp(fd.cFileName, L".") == 0 ||wcscmp(fd.cFileName, L"..") == 0)) { if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { arDirectoryNeedToBeDeleted.push_back(fullname); CollectDeleteDirectory(firstroot, fullname, outdir); } } b = ::FindNextFile(hf, &fd); } ::FindClose(hf); } int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT) { CMessageLoop theLoop; _Module.AddMessageLoop(&theLoop); CEncryptXML dlgMain; if (dlgMain.Create(NULL) == NULL) { ATLTRACE(_T("Main dialog creation failed!\n")); return 0; } dlgMain.ShowWindow(nCmdShow); dlgMain.CenterWindow(); int nRet = theLoop.Run(); _Module.RemoveMessageLoop(); return nRet; } int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPreInstance*/, LPTSTR lpstrCmdLine, int nCmdShow) { HRESULT hRes = ::CoInitialize(NULL); ATLASSERT(SUCCEEDED(HRes)); ::DefWindowProc(NULL, 0, 0, 0L); AtlInitCommonControls(ICC_BAR_CLASSES); hRes = _Module.Init(NULL, hInstance); ATLASSERT(SUCCEEDED(hRes)); int nRet = Run(lpstrCmdLine, nCmdShow); _Module.Term(); ::CoUninitialize(); return nRet; }
实际使用的过程中,最常导致机密失败的原因便是加密文件选择了“只读”属性,去除只读属性即可。
原文地址:http://blog.csdn.net/coffeecato/article/details/41789161