吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2702|回复: 10
收起左侧

[C&C++ 原创] 【第二版】自己设计的一个加密、解密算法;C++实现

  [复制链接]
RainPPR 发表于 2022-12-13 11:11
本帖最后由 RainPPR 于 2022-12-19 11:12 编辑

声明:此算法完全是学习,未考虑算法效率、内存占用等。仅供学习使用!

更新日志

2022年12月14日9时0分
1. 使用 unsigned long long 代替 long long 防止 UB.
2. 随机数 rand 对 0x8000 取模,使各环境保持一致.
2022年12月19日11时0分
1. 更新下载链接

〇、目录

一、思路来源
二、实现过程
   1. 密钥生成
   2. 一次加密
   3. 二次加密
三、成品分享
   1. 库文件&使用说明
   2. 打包程序

一、思路来源

加密,是以某种特殊的算法改变原有的信息数据,使得未授权的用户即使获得了已加密的信息,但因不知解密的方法,仍然无法了解信息的内容。——百度

加密算法的作用就是把一段信息(明文)通过某种算法,转化为不能/不易看懂的信息(密文)。

作用:防止个人情报的泄漏,防止数据被更改,确保数据发自特定的一方、传给特定的一方。

由上文可知,加密在当今信息时代的重要性,于是我就设计了一个加密、解密算法。

二、实现过程

1. 密钥生成

        我构想的加密算法,可以让接受者清楚加密的时间。于是我就想到了“UNIX时间戳”,C++中用 <ctime> 可以方便地生成。  

#include <ctime>

using namespace std;

unsigned long long t1 = time(0);

        但是C++中的 time(0) 是按秒计的,也就是说,一秒内这样生成的所有密钥都会是一致的;而且如果其他人知道了加密的大概时间,就可以很容易地暴力枚举进行破解了。
        于是,我在 time(0) 的基础上,乘上一个 rand()。因为不同环境下 rand() 的结果不同(但都是 0 到至少 0x7fff),所以对 0x8000 取模。

#include <ctime>
#include <cstdlib>

using namespace std;

srand(time(0));
unsigned long long t1 = time(0);
unsignedlong long t2 = rand() % 0x8000;

        然后就是怎么把这两个数转换为一个密钥了。我用了非常简单的算法:×。没错,就是乘法……
        但是这样生成的随机数是在一个较小的范围 [0, 32767] 内的,所以我将随机数平方,再乘以时间戳。为了“美观”,再乘上一个大数 20090312。(猜猜这是什么意思 'u'
        你可能已经发现了,我用了 unsigned long long 存储数据,超过最大值后会“溢出”,自动取模:

在 C++ 中
int 溢出是 Undefined Behavior,是否取会模取决于编译器。
unsigned int 溢出是 Define Behavior,在溢出时自动取模。
#include <ctime>
#include <cstdlib>

using namespace std;

srand(time(0));
unsigned long long t1 = time(0);
unsignedlong long t2 = rand() % 0x8000;
unsigned long long t = t1 * (t2 * t2) * 20090312; // 习惯性打括号

        这么大的数,一时想不到怎么用来加密字符串,于是我有了类似 base64 的一种编码方式,将这个数转换为一个字符串:先生成“字典”,然后用“进制转换”的方式将数字转换为大进制数,再对应为字符串。
        然后我把整个算法打包为一个 class 类,方便调用。

// File: pcode.h

#include <ctime>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <string>

#pragma once

using namespace std;

class _PCODE
{
    private:

        // typedef
        typedef unsigned long long ll;
        typedef pair<ll, ll> PLL;

        // rand % 0x7fff

        // get time
        PLL get_time()
        {
            ll t1 = time(0);
            //ll t2 = clock();
            ll t2 = rand() % 0x8000;
            return {t1, t2};
        }

        // encode
        vector<char> ppr_code;

        // time to str
        string time_str(PLL tt)
        {
            ll t = tt.first * (tt.second * tt.second) * 20090312;

            string res;
            while (t)
            {
                res.push_back(ppr_code[t % ppr_code.size()]);
                t /= ppr_code.size();
            }

            return res;
        }

    public:

        _PCODE()
        {
            srand(time(0));

            for (int i = 0 ; i < 26 ; ++i)
            {
                if (i % 2 == 0)
                {
                    ppr_code.push_back('a' + i);
                    ppr_code.push_back('A' + i);
                }
                else
                {
                    ppr_code.push_back('A' + i);
                    ppr_code.push_back('a' + i);
                }
                if (i % 3 == 0)
                    ppr_code.push_back('0' + i / 3);
            }
            ppr_code.push_back('9');
            ppr_code.push_back('+');
            ppr_code.push_back('=');
            ppr_code.push_back('!');
            ppr_code.push_back('-');
            ppr_code.push_back('@');
            ppr_code.push_back('$');
            ppr_code.push_back('%');
            ppr_code.push_back('&');
        }

        // get code (now)
        string getnow(ll *t1, ll *t2)
        {
            PLL t = get_time();
            *t1 = t.first;
            *t2 = t.second;
            return time_str(t);
        }
        string getnow()
        {
            PLL t = get_time();
            return time_str(t);
        }

        // number to code
        string encode(ll t1, ll t2)
        {
            PLL t = {t1, t2};
            return time_str(t);
        }
} pcode;

2. 一次加密

        在上一节中,我们已经生成了字符串密钥,接下来就是加密的过程了。(这一节叫做“一次加密”,说明接下来还有一次加密过程)
        算法很简单,重复密钥多次,使密钥与明文长度一致,或者只取密钥的前一部分。然后密钥与明文的每一位进行 ^ 抑或运算。
        (代码与下一节合在一起)

3. 二次加密

        看到上面那节,你发现问题了吗?
        没错,抑或运算的结果对应的符号有部分不在可见符号范围内(我用的是 ANSI 编码),于是,我用 Base64 编码进行了二次编码。

        Base64编码算法请见(论坛里找的)https://www.52pojie.cn/thread-1715164-1-1.html。这里我加了一个 namespace 命名空间,方便调用。

// File: base64.h

#include <string>
#include <cstring>

#pragma once

namespace _base64
{
// 编码表
    static const char base64en[] =
    {
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',  'I', 'J', 'K',
        'L', 'M', 'N', 'O', 'P',  'Q', 'R', 'S', 'T', 'U', 'V',
        'W', 'X',   'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
        'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
        's', 't', 'u', 'v',  'w', 'x', 'y', 'z', '0', '1', '2',
        '3', '4', '5', '6', '7', '8', '9', '+', '/'
    };

// 解码表
    static const unsigned char base64_suffix_map[256] =
    {
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 255,
        255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 253, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
        52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255,
        255, 254, 255, 255, 255,   0,   1,   2,   3,   4,   5,   6,
        7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,
        19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,
        255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,
        37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
        49,  50,  51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255
    };

    std::string base64_encode(const char *data)
    {
        std::string out = "";

        // 长度计算
        int data_len = strlen(data);
        if (data_len == 0)
        {
            return "";
        }

        char c = '\0';
        char last_c = '\0';

        for (int i = 0; i < data_len; i++)
        {
            c = data[i];
            switch (i % 3)
            {
                case 0:
                    out.push_back(base64en[(c >> 2) & 0x3f]);
                    break;
                case 1:
                    out.push_back(base64en[(last_c & 0x3) << 4 | ((c >> 4) & 0xf)]);
                    break;
                case 2:
                    out.push_back(base64en[((last_c & 0xf)) << 2 | ((c >> 6) & 0x3)]);
                    out.push_back(base64en[c & 0x3f]);
                    break;
            }
            last_c = c;
        }

        if (data_len % 3 == 1)
        {
            out.push_back(base64en[(c & 0x3) << 4]);
            out.push_back('=');
            out.push_back('=');
        }

        if (data_len % 3 == 2)
        {
            out.push_back(base64en[(c & 0xf) << 2]);
            out.push_back('=');
        }

        return out;
    }

    std::string base64_decode(const char *data)
    {
        std::string output;

        int data_len = strlen(data);
        unsigned char c = '\0';

        int t = 0, y = 0;
        int g = 3;

        for (int x = 0; x < data_len; x++)
        {
            c = base64_suffix_map[data[x]];

            if (c == 255)
                output.clear();
            if (c == 253)
                continue;   // 对应的值是换行或者回车
            if (c == 254)
            {
                c = 0;      // 对应的值是'='
                g--;
            }

            t = (t << 6) | c;

            if (++y == 4)
            {
                output.push_back((t >> 16) & 0xff);
                if (g > 1)
                    output.push_back((unsigned char)((t >> 8) & 0xff));
                if (g > 2)
                    output.push_back((unsigned char)(t & 0xff));
                y = t = 0;
            }
        }

        return output;
    }
}

        编码总程序(库文件)。这里我加了一个 class 类,方便调用。

// File: ppr.h

#include <string>
#include <cstring>

#include "pcode.h"
#include "base64.h"

#pragma once

using namespace std;

class _PPRCode
{
    private:

        //typedef
        typedef unsigned long long ll;

    public:

        // 编码
        string encode(string str, ll *t1, ll *t2)
        {
            string pwd = pcode.getnow(t1, t2);

            string ans;
            for (int i = 0, j = 0 ; i < str.size() ; ++i, ++j)
            {
                if (j == pwd.size())
                    j = 0;
                ans += char(str[i] ^ pwd[j]);
            }

            ans = _base64::base64_encode(ans.c_str());

            return ans;
        }

        // 解码
        string decode(string str, ll t1, ll t2)
        {
            str = _base64::base64_decode(str.c_str());

            string pwd = pcode.encode(t1, t2);

            string ans;
            for (int i = 0, j = 0 ; i < str.size() ; ++i, ++j)
            {
                if (j == pwd.size())
                    j = 0;
                ans += char(str[i] ^ pwd[j]);
            }

            return ans;
        }
} pprc;

三、成品分享

1. 库文件&使用说明

        库文件源码上面有(有 // File: *.h 的都是)。方便下载,打包一个云盘:

链接:https://www.123pan.com/s/JavSVv-NqLnH
提取码:52pj

        使用说明

// 1. 加入头文件
#include "ppr.h"

// 2. 编码
std::string str = "RainPPR";    // 明文(std::string)
unsigned long long t1;                   // 将要返回的密钥1
unsigned long long t2;                   // 将要返回的密钥2
std::string ans = pprc.encode(str, &t1, &t2);  // ans 中的即为密文

// 3. 解码
std::string str = "Jg4FKHQ9Jg==";    // 密文(std::string)
unsigned long long t1 = 1670900298;           // 密钥1
unsigned long long t2 = 17993;                // 密钥2
std::string ans = pprc.decode(str, t1, t2);    // ans 中的即为明文

2. 打包程序

        成品发在原创区了,详见:https://www.52pojie.cn/thread-1726292-1-1.html

在这里也感谢我的同学——徐梓玉,她给这个软件带来了一点灵感。

免费评分

参与人数 6威望 +1 吾爱币 +11 热心值 +6 收起 理由
zhczf + 1 我很赞同!
top7777 + 1 + 1 用心讨论,共获提升!
gunxsword + 1 + 1 热心回复!
苏紫方璇 + 1 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
seawaycao + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
binqi + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

lsy_loren 发表于 2022-12-13 11:25
膜拜大神!
binqi 发表于 2022-12-13 11:30
飘零星夜 发表于 2022-12-13 11:53
真棒, 我目前使用得就是类似得算法,RC4 +BASE64 。 用以实现空中升级这个二逼功能。
seawaycao 发表于 2022-12-13 12:10
谢谢分享,收藏备用
嘛名字不名字的 发表于 2022-12-13 22:00
能搞一个CPK后缀名的  解密软件吗?
chinasugar 发表于 2022-12-14 01:22
很不错的思路,学习中。
sxqxyfw 发表于 2022-12-14 09:13
谢谢分享,收藏学习以备以后借鉴使用。正好我也经常使用C++
MarTao2020 发表于 2022-12-31 01:32
在这里的都是大佬
cnqv 发表于 2023-1-3 20:30
谢谢分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 02:26

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表