• 字符串加解密代码


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

    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

  • 相关阅读:
    sratookit
    转录组测序
    单菌基因组测序常见问题
    微生物测序样本准备方法总结
    Review:Microbiota, metagenome, microbiome傻傻分不清
    扩增子、宏基因组测序问题集锦
    扩增子图表解读8网络图:节点OTU或类Venn比较
    扩增子图片解读7三元图
    扩增子图表解读5火山图:差异OTU的数量及变化规律
    扩增子图表解读6韦恩图:比较组间共有和特有OTU或分类单元
  • 原文地址:https://www.cnblogs.com/rhcad/p/1731924.html
Copyright © 2020-2023  润新知