zoukankan      html  css  js  c++  java
  • 字符串加解密代码

    今天把很久以前使用的字符串简单加解密代码仔细检查了一遍,发现个别问题,现在已经整理好了,该算法的特点如下:

    1、采用逐个字符移位变换、相邻三个字符按位错位的对称加密算法

    2、支持对汉字和不可见字符等各种字符的加密,可以说是对任意字符组成的串都可加密

    3、支持源字符串中包含多个’\0’零字符,这样就可以把简单字符串的加密扩展到XML内容、文件内容的加解密上。

    4、密文采用Base64编码,由大写字母、小写字符、数字、下划线、小数点组成,共64个不同的可见字符

    由于算法内部是针对字节进行加密的,所以将函数参数定为char*,对于UNICODE字符串可先转换为ANSI串再调用。当然,如果程序是老式的ANSI串编码,例如VC++6.0默认产生的程序,则不需要进UNICODE转换。

    下面是实际项目中的调用举例:

    --------读取密码----------

    // 读取出已加密的密码文字
    std::wstring password(secOption->GetString(L"password"));

    // 转换为ANSI串后再解密
    m_password = std::a2w(StringDecrypt(std::w2a(password).c_str())).c_str();

    ---------保存密码--------------

    // 由于每次加密都会生成随机的密文文字,故仅在输入密码后才保存
    if (m_bPasswordChanged)
    {
        std::wstring password(towstr(m_password));

        // 将明文密码转换为ANSI串,然后加密
        password = std::a2w(StringEncrypt(std::w2a(password).c_str()));

        // 保存经过加密的密码到文件中
        secOption->SetString(L"password", password.c_str());

        m_bPasswordChanged = FALSE;
    }

    附源码:

    StrEncrypt.h

    //! \file StrEncrypt.h
    //! \brief 定义字符串加解密函数 StringEncrypt/StringDecrypt

    #pragma once

    //! 文字串加密
    /*!
        \ingroup _GROUP_UTILFUNC
        \param srcstr 明文串,支持汉字等各种字符,可包含多个0字符,
            对于UNICODE串要先转换为ANSI串
        \param srclen 明文串的字符数,默认取strlen(srcstr),
            如果串中包含多个0字符时可指定实际字符数
        \return 生成的加密串,由字母、数字、'_'、'.'组成,
            长度为4的倍数,至少为4,外加0结束符,len= (3 + len(srcstr))/3*4
    */
    std::string StringEncrypt(const char* srcstr, int srclen = -1);

     

    //! 字符串解密
    /*!
        \ingroup _GROUP_UTILFUNC
        \param srcstr 已加密的串,对于UNICODE串要先转换为ANSI串,字符数应为4的倍数且至少为4
        \return 生成的明文串,长度为 len(srcstr))/4*3。\n
            如果加密时的明文中包含了多个0字符,则此处得到的串中也有这些0字符,可遍历得到全部字符。
    */
    std::string StringDecrypt(const char* srcstr);

    ----------------------------------------------------------------

    StrEncrypt.cpp:

    #include "stdafx.h"
    #include "StrEncrypt.h"

     

    // 将一个索引数(0到63)转换为字符(字母、数字、'_'、'.') 
    static char UnIndex64(BYTE nIndex)
    {
        char ch;

        nIndex %= 64;                    // 取到[0,64)范围内

        if (nIndex < 26)                // [0,26)返回大写字母
        {
            ch = (char)('A' + nIndex);
        }
        else if (nIndex < 52)            // 26+[0,26)返回小写字母
        {
            ch = (char)('a' + nIndex - 26);
        }
        else if (nIndex < 62)            // 52+[0,10)返回数字
        {
            ch = (char)('0' + nIndex - 52);
        }
        else if (nIndex == 62)            // 62返回'_'
        {
            ch = '_';
        }
        else if (nIndex == 63)            // 63返回'.'
        {
            ch = '.';
        }
        else
        {
            ch = 'A';
        }

        return ch;
    }

     

    // Index64: 将一个字符(字母、数字、'_'、'.')转换为索引数(0到63)

    static BYTE Index64(char ch)
    {
        BYTE nIndex;

        if (_istupper(ch))
        {
            nIndex = ch - 'A';
        }
        else if (_istlower(ch))
        {
            nIndex = 26 + ch - 'a';
        }
        else if (_istdigit(ch))
        {
            nIndex = 52 + ch - '0';
        }
        else if (ch == '_')
        {
            nIndex = 62;
        }
        else if (ch == '.')
        {
            nIndex = 63;
        }
        else
        {
            nIndex = 0;
        }

        return nIndex;
    }

     

    // ToBase64: 将一个索引字符串转换为由字符(字母、数字、'_'、'.')组成的字符串

    // instr 索引字符串,长度为len,为3的倍数
    // len   instr的字符个数,为3的倍数
    // outstr 填充由字符(字母、数字、'_'、'.')组成的字符串,长度为4的倍数
    static void ToBase64(const char* instr, int len, char* outstr)
    {
        ASSERT(instr && len > 0 && len % 3 == 0);

        int i, j;
        BYTE ch1, ch2, ch3;

        i = 0;
        j = 0;
        while (i + 2 < len)
        {
            ch1 = (BYTE)instr[i];
            ch2 = (BYTE)instr[i + 1];
            ch3 = (BYTE)instr[i + 2];

            outstr[j] = UnIndex64(ch1 >> 2);
            outstr[j + 1] = UnIndex64(((ch1 & 0x3) << 4) | (ch2 >> 4));
            outstr[j + 2] = UnIndex64(((ch2 & 0x0f) << 2) | (ch3 >> 6));
            outstr[j + 3] = UnIndex64(ch3 & 0x3f);

            i += 3;
            j += 4;
        }
        outstr[j] = '\0';
    }

     

    // UnBase64: 将一个由字符(字母、数字、'_'、'.')组成的字符串转换为索引字符串

    // instr 由字符(字母、数字、'_'、'.')组成的字符串,长度为len,为4的倍数
    // len   instr的字符个数,为4的倍数
    // outstr 索引字符串,长度为3的倍数
    static void UnBase64(const char* instr, int len, char* outstr)
    {
        ASSERT(instr && len % 4 == 0);

        int i, j;
        BYTE ch1, ch2, ch3, ch4;

        i = 0;
        j = 0;
        while (i + 3 < len)
        {
            ch1 = Index64(instr[i]);
            ch2 = Index64(instr[i + 1]);
            ch3 = Index64(instr[i + 2]);
            ch4 = Index64(instr[i + 3]);

            outstr[j] =  (ch1 << 2) | ((ch2 >> 4) & 0x3);
            outstr[j + 1] = (ch2 << 4) | ((ch3 >> 2) & 0xf);
            outstr[j + 2] = (ch3 << 6) | ch4;

            i += 4;
            j += 3;
        }
        outstr[j] = '\0';
    }

     

    // EncryptChar: 对一个字符进行移位变换:最高位不变,其余7位对调(1-7,2-6,3-5)

    static char EncryptChar(char c)
    {
        BYTE x = 0;

        x += (c & 0x80);
        x += (c & 0x40) >> 6;
        x += (c & 0x20) >> 4;
        x += (c & 0x10) >> 2;
        x += (c & 0x08);// << 3;
        x += (c & 0x04) << 2;
        x += (c & 0x02) << 4;
        x += (c & 0x01) << 6;

        return x;
    }

     

    static inline char randchar()
    {
        char c = (char)rand();
        return 0 == c ? '\xAA' : c;
    }

     

    // StringEncrypt: 加密文字串,输出的串的长度为(3 + len(srcstr))/3*4

    std::string StringEncrypt(const char* srcstr, int srclen)
    {
        if (srclen < 0)
        {
            srclen = (NULL == srcstr) ? 0 : strlen(srcstr);
        }

        int inlen = (1 + srclen + 2) + 1;
        int outlen = (3 + srclen) / 3 * 4 + 1;

        char *buf = new char[inlen + outlen];
        char *inbuf = buf;
        char *outbuf = buf + inlen;

        memset(buf, 0, sizeof(char) * (inlen + outlen));

        // 复制源串到(inbuf+1),每个字符进行移位变换
        for (int i = 0; i < srclen; i++)
        {
            inbuf[i + 1] = EncryptChar(srcstr[i]);
        }

        // 设置长度标记字符 inbuf[0]
        // 移位变换可能产生0字符,用最低两位代表inbuf的长度, 00:3n, 01:3n+1,10:3n+2
        //
        srand( (unsigned)time(NULL) );
        inbuf[0] = randchar() & (~0x03);    // 最低两位为0时,leadlen % 3 == 0

        int actlen = srclen + 1;
        if (actlen % 3 == 1)        // 原长3n+1,补两个随机字符保证inbuf长度为3n
        {
            inbuf[0] |= 0x01;
            inbuf[actlen] = randchar();
            inbuf[actlen + 1] = randchar();
            actlen += 2;
        }
        else if (actlen % 3 == 2)    // 原长3n+2,补1个随机字符保证inbuf长度为3n
        {
            inbuf[0] |= 0x02;
            inbuf[actlen] = randchar();
            actlen++;
        }

        // 从inbuf转换出outbuf,outbuf由字母、数字、'_'、'.'组成,长度为4的倍数
        ToBase64(inbuf, actlen, outbuf);

        std::string strResult(outbuf);

        delete[] buf;

        return strResult;
    }

     

    // StringDecrypt: 解密文字串,输出的串的长度为 len(srcstr))/4*3

    std::string StringDecrypt(const char* srcstr)
    {
        int srclen = (NULL == srcstr) ? 0 : strlen(srcstr) / 4 * 4;
        int len = srclen * 3 / 4;

        if (0 == len)
        {
            return "";
        }

        char *chBuf = new char[len + 1];

        UnBase64(srcstr, srclen, chBuf);

        if (1 == (chBuf[0] & 0x03))
            len -= 2;
        else if (2 == (chBuf[0] & 0x03))
            len--;
        chBuf[len] = 0;

        for (int i = 1; i < len; i++)
        {
            chBuf[i] = EncryptChar(chBuf[i]);
        }

        std::string strResult(chBuf + 1, len - 1);

        delete[] chBuf;

        return strResult;
    }

     

    --------------------------------------------------------

    Unicode和Ansi串的转换:

    //! \file ConvStr.h
    //! \brief 定义UNICODE串和ANSI串的相互转化函数

    #pragma once

    _STD_BEGIN

    //! UNICODE串转换为ANSI串, std::w2a
    /*!
        \ingroup _GROUP_UTILFUNC
    */
    inline std::string w2a(LPCWSTR s)
    {
        std::string str;
        int wlen = (NULL == s) ? 0 : (int)wcslen(s);
        if (wlen > 0)
        {
            long len = WideCharToMultiByte(CP_ACP, 0, s, wlen, NULL, 0, NULL, NULL);
            str.resize(len);
            WideCharToMultiByte(CP_ACP, 0, s, wlen,
                const_cast<char*>(str.data()), len, NULL, NULL);
        }

        return str;
    }

     

    //! UNICODE串转换为ANSI串, std::w2a
    /*!
        \ingroup _GROUP_UTILFUNC
    */
    inline std::string w2a(const std::wstring& s)
    {
        return w2a(s.c_str());
    }

     

    //! ANSI串转换为UNICODE串, std::a2w
    /*!
        \ingroup _GROUP_UTILFUNC
    */
    inline std::wstring a2w(LPCSTR s)
    {
        std::wstring wstr;
        int len = (NULL == s) ? 0 : (int)strlen(s);
        if (len > 0)
        {
            int wlen = MultiByteToWideChar(CP_ACP, 0, s, len, NULL, 0);
            wstr.resize(wlen);
            MultiByteToWideChar(CP_ACP, 0, s, len,
                const_cast<LPWSTR>(wstr.data()), wlen);
        }

        return wstr;
    }

     

    //! ANSI串转换为UNICODE串, std::a2w
    /*!
        \ingroup _GROUP_UTILFUNC
    */
    inline std::wstring a2w(const std::string& s)
    {
        return a2w(s.c_str());
    }

     

    #ifdef _UNICODE
    inline std::wstring w2t(LPCWSTR s) { return s; }
    inline std::wstring w2t(const std::wstring& s) { return s; }
    inline std::wstring t2w(LPCTSTR s) { return s; }
    #else
    inline std::string w2t(LPCWSTR s) { return w2a(s); }
    inline std::string w2t(const std::wstring& s) { return w2a(s); }
    inline std::wstring t2w(LPCTSTR s) { return a2w(s); }
    #endif

    _STD_END

  • 相关阅读:
    用 ArcMap 发布 ArcGIS Server FeatureServer Feature Access 服务 PostgreSQL 版本
    ArcMap 发布 ArcGIS Server OGC(WMSServer,MapServer)服务
    ArcScene 创建三维模型数据
    ArcMap 导入自定义样式Symbols
    ArcMap 导入 CGCS2000 线段数据
    ArcMap 导入 CGCS2000 点坐标数据
    ArcGis Server manager 忘记用户名和密码
    The view or its master was not found or no view engine supports the searched locations
    python小记(3)操作文件
    pytest(2) pytest与unittest的区别
  • 原文地址:https://www.cnblogs.com/rhcad/p/1731924.html
Copyright © 2011-2022 走看看