游戏配置文件加密工具(附源码)

引言:

这是开发PC游戏《海战世界》时用到的配置文件加密工具,游戏开发难免要用到配置文件,而其中某些数据开发者并不期望用户获知或是修改,通常会对一些配置文件进行加密。一般是用一个批量的加密工具,统一对配置文件进行加密。

考虑到加密、解密的效率及对安全性的需求,选择了最常用的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;
}


最后:

 

实际使用的过程中,最常导致机密失败的原因便是加密文件选择了“只读”属性,去除只读属性即可。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值