base64加解密c++实现

  • Base64编码原理
    • 1、加密原理
    • 2、c++实现加解密过程
  • IDA中算法分析
    • std::string的使用总结
    • base64加密分析
    • 小插曲-base64隐写
    • 源码
    • 实战中的魔改例子
      • 1、通过异或还原表
      • 2、通过移位产生表

Base64编码原理

目前单字符最大为3Byte(特殊字符),汉字(2Byte)、字母(1Byte)…
而base64则是通过位运算加索引表将3个字符的内容编码为4个字符,也就是编码当前所有的单字符是完全够用的,base64能实现不可见字符和图片的传递,非常的便捷实用。

1、加密原理

将3个8bit的转换为4个6bit的数据,再通过索引表转换为4个可见字符,如下:

base64的正常索引表为:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
上述即明文为:"son"时 先将三个字符依次转化为 83 111 110
对应二进制则为 01010011 01101111 01101110
将则24位拼在一起之后4等分(6个一组):
010100 110110 111101 101110
之后转化为10进制,作为下标进行索引,如上图所示。

对一个长为len的明文,重复进行len//3次,如果len为三的倍数那么密文长度为(4/3)len,如果len的长度不为3的倍数,则需要额外的补充’\0’直到分组为3的倍数,补充几次‘/0’则在密文尾部添加几个‘=’,最终明文长度仍为4的倍数

2、c++实现加解密过程

加密函数主体:
核心为通过移位运算和&运算,将24bit划分为4组6bit接着转为10进制,进行索引,同时对明文不满足3的倍数进行填充。

string base64_encode(char*m,int len){ //转入的明文m 和 明文长度lenstring cipher;char tmp_3[3];//3个一组 临时存放 char enbase_4[4];//3->4  int i=0;//了解base64的原理后直到是3->4所以通过一个循环来实现过程while(len){tmp_3[i]= *(m++);//将明文内容3个一组引入到tmp临时空间中去i++;if(i==3){ //如果得到3个字符,则进行位运算enbase_4[0]=(tmp_3[0]&(0xfc))>>2; //0xfc == 0x11111100 enbase_4[1]=((tmp_3[0]&(0x03))<<4)+((tmp_3[1]&0xf0)>>4);enbase_4[2]=((tmp_3[1]&0x0f)<<2)+((tmp_3[2]&0xc0)>>6);enbase_4[3]=tmp_3[2]&0x3f;//通过位运算实现3个8bit一组 -> 4个6bit一组 for(int j=0;j<4;j++){cipher+=base_table[enbase_4[j]]; //索引 }i=0;}len--;} //上述循环将len//3 组数据转为base64 ,最优情况 i=0&&len==0;其余则是i=1 || i=2 if(i){for(int j=i;j<3;j++)tmp_3[j]='\0'; //补充到三位  每一个字节补'\0' 即 0b00000000enbase_4[0]=(tmp_3[0]&(0xfc)) >>2; enbase_4[1]=((tmp_3[0]&(0x03))<<4) + ((tmp_3[1]&0xf0)>>4);enbase_4[2]=((tmp_3[1]&0x0f)<<2) + ((tmp_3[2]&0xc0)>>6); // 三次即可,如果i=2的话 最多只有三组6为二进制的值不全为0,且最后一组的后两位一定为0for(int j=0;j<i+1; j++) //注意为j<i+1  1个8bit 分为2个6bit {cipher+=base_table[enbase_4[j]];}while(i!=3){cipher+='='; //缺几个字节 就补几个'=' i++; }}return cipher;
}

解密函数主体:
解密则是加密的逆过程,实现4->3 ,并且是找出密文在base64表中的下标,将所有找出的下标8个一组转ASCII,得到最初的明文,特殊是对于尾部有‘=’的处理

string base64_decode(char*c,int len){string m;char tmp_4[4];char debase_3[3];//实现4B->3B  int i=0;int index=0; //表示当前在密文中的下标 while(len--&&c[index]!='='){ //读完密文或读到‘=’退出循环tmp_4[i]=base_table.find(c[index])&0x3f; //通过find函数 找到下标对应的值i++;index++;if(i==4){debase_3[0]=((tmp_4[0]&0x3f)<<2) + ((tmp_4[1]&0x30)>>4);debase_3[1]=((tmp_4[1]&0xf)<<4) + ((tmp_4[2]&0x3c)>>2);debase_3[2]=((tmp_4[2]&0x3)<<6) + (tmp_4[3]&0x3f);//注意位运算的优先级 for(int j =0;j<3;j++)m+=(char)debase_3[j];i=0;}}if(i){ // 如果i不为0 则i表示 '=' 在4个字符中的下标 for(int j=i;j<4;j++)tmp_4[j]='\0';//把所有等号的位置全补上0debase_3[0]=((tmp_4[0]&0x3f)<<2) + ((tmp_4[1]&0x30)>>4);debase_3[1]=((tmp_4[1]&0xf)<<4) + ((tmp_4[2]&0x3c)>>2); //最多转成两个字符for(int j=0;j<i-1;j++)  //j<i-1 比如 i=3时出现'=' 那么证明一个等号 故明文有两位 m+=debase_3[j];}return m;
}

IDA中算法分析

补全主函数后生成EXE文件,用IDA64对EXE文件进行静态分析。

用c++实现base64编码的时候用到了string库,分析看起来比较复杂,去了解了一下std::string库的常见使用。

std::string的使用总结

std::string s1;
std::string s3(s2);
std::string s2(“this is a string”);
begin 得到指向字符串开头的Iterator
end 得到指向字符串结尾的Iterator
rbegin 得到指向反向字符串开头的Iterator
rend 得到指向反向字符串结尾的Iterator
size 得到字符串的大小
length() 和size函数功能相同
max_size 字符串可能的最大大小
capacity 在不重新分配内存的情况下,字符串可能的大小
empty 判断是否为空
operator[] 取第几个元素,相当于数组
c_str 取得C风格的const char* 字符串
data 取得字符串内容地址
operator= 赋值操作符
reserve 预留空间
swap 交换函数
insert 插入字符
append 追加字符
push_back 追加字符
erase 删除字符串
clear 清空字符容器中所有内容
resize 重新分配空间
assign 和赋值操作符一样
replace 替代
copy 字符串到空间
find 查找,返回基于0的索引号
rfind 反向查找
find_first_of 查找包含子串中的任何字符,返回第一个位置
find_first_not_of 查找不包含子串中的任何字符,返回第一个位置
find_last_of 查找包含子串中的任何字符,返回最后一个位置
find_last_not_of 查找不包含子串中的任何字符,返回最后一个位置
substr(n1,len) 得到字符串从n1开始的长度为len的子串
比较字符串(支持所有的关系运算符)
compare 比较字符串
operator+ 字符串链接
operator+= += 操作符
operator== 判断是否相等
operator!= 判断是否不等于
operator< 判断是否小于
operator>> 从输入流中读入字符串
operator<< 字符串写入输出流
getline 从输入流中读入一
————————————————
版权声明:本文为CSDN博主「哀酱」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u010821666/article/details/77934510

通过一定的C++基础,std::string 大致能辨识,string本身是打包好的一个类,所以有着构造和析构函数这种赋值。

base64加密分析

程序流程是对输入进行了base64加密,之后和一个字符串解密,一般题目中只要识别出编码方式便能简单破解,为了深入学习base64编码原理,下面主要分析base64的加密算法。


第一部分,对明文字符串进行3个一组分组,每一组进行分割和base索引。
从上图也可以看出base64算法明显的特征:分组进行位运算实现3变4,另外就是base64索引表。

源代码将base64的表写成了static,存放在全局变量区,内部文件可见,外部文件不可见,所以要获得表需要进行动态调试,跟进v4便可得到表,不太清楚为什么base_table显示UNKNOW。


当然如果把static string base_table换成其他内容则变成了一道base64换表的题,并且需要动态调试找到索引表。

接下来则是对明文不是3的倍数的处理:
即如果2个字符则补一个’='且密文经过换表的内容为2+1=3
二进制位 xxxxxx xxxxxx xxxx00 000000 也就是只要前3部分的索引值,剩余一位补‘=’。
同理如果1个字符则要补两个‘=’那么分割的二进制位 xxxxxx xx0000 000000 000000 也就是只有前两部分的值为特殊值,剩余两位补‘=’。

小插曲-base64隐写

通过上述补位也可以看出,补充的0有部分是参与base64表的索引的,则也为我们提供了一个思路,可不可以不用0来补,用其他相用的数据是否可能起到更好的效果,这就与MISC中的base64隐写有了一定的联系,即一个等号时,第三部分低二位的值用明文来填充,两个等号时第二部分的低4位用明文来填充。
即:
xxxxxx xxxxxx xxxxab 000000
xxxxxx xxabcd 000000 000000

a,b,c,d…代表某一二进制数据。可见base64隐写虽然可能对明文的最后一个字母有所影响,但是不影响解密内容,毕竟只是改写了填充部分。
附上解密代码:

import base64
a=("")
mode=("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")       #base64 mode码表
c=("")
f = open("base64.txt","r")                 #读取文件
line = f.readline()                         #一行一行读取 下标指针自动向后移动
while line:if("=" in line):a=line.replace('=','')[-2:]     #去掉‘=’留下最后一个字符 文件读取最后一位为‘/n'print(a,end="")                    #这里用来检测是否出错了num=(line.count('='))*2         #等号个数来决定截取二进制字符的个数  一个'='截取两个 二个'='截取4个c=c+(bin(mode.index(a[0])).replace("0b",'')[-(num):].zfill(num))     #这里是关键,对其进行查表对号,再进行二进制转换筛选line = f.readline()              #.zfill()是在左边填0 补成num位else:line = f.readline()      #没有等号就跳过continue
f.close()
for i in range (0,len(c),8):print(chr(int(c[i:i+8],2)),end='')  #输出    8位二进制转为 10进制 之后转ascii码

根据脚本和上述解释,理解起来感觉更加轻松。

源码

最终附上自己写的源码,可能在健壮性和效率等有些方面不足或存在错误,还请各位师傅们指正。

#include<iostream>
#include<cstring>
using namespace std;
string base64_encode(char*m,int len);
string base64_decode(char*c,int len);
static string base_table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int main(){char m[100];string ss;cout<<"pleas tell me your secret:";cin>>m;ss=base64_encode(m,strlen(m)); string secret="ZmxhZ3tUaGlzX2lzX215X2Jhc2V9";if(secret==ss)cout<<"you get it"<<endl;else cout<<"try a again!"<<endl; return 0;
}string base64_encode(char*m,int len){string cipher;char tmp_3[3];//3个一组 临时存放 char enbase_4[4];//3->4  int i=0;while(len){//tmp_3[i] = m[i]; 错误的索引 i被改变了tmp_3[i]= *(m++);i++;if(i==3){enbase_4[0]=(tmp_3[0]&(0xfc))>>2; //0xfc == 0x11111100 enbase_4[1]=((tmp_3[0]&(0x03))<<4)+((tmp_3[1]&0xf0)>>4);enbase_4[2]=((tmp_3[1]&0x0f)<<2)+((tmp_3[2]&0xc0)>>6);enbase_4[3]=tmp_3[2]&0x3f;//通过位运算实现3个8bit一组 -> 4个6bit一组 for(int j=0;j<4;j++){cipher+=base_table[enbase_4[j]]; //索引 }i=0;}len--;} //上述循环将len//3 组数据转为base64 ,最优情况 i=0&&len==0;其余则是i=1 || i=2 if(i){for(int j=i;j<3;j++)tmp_3[j]='\0'; //补充到三位  每一个字节补'\0' 即 0b00000000enbase_4[0]=(tmp_3[0]&(0xfc)) >>2; enbase_4[1]=((tmp_3[0]&(0x03))<<4) + ((tmp_3[1]&0xf0)>>4);enbase_4[2]=((tmp_3[1]&0x0f)<<2) + ((tmp_3[2]&0xc0)>>6); // 三次即可,如果i=2的话 最多只有三组6为二进制的值不全为0,且最后一组的后两位一定为0for(int j=0;j<i+1; j++) //注意为j<i+1  1个8bit 分为2个6bit {cipher+=base_table[enbase_4[j]];}while(i!=3){cipher+='='; //缺几个字节 就补几个'=' i++; }}return cipher;
}string base64_decode(char*c,int len){string m;char tmp_4[4];char debase_3[3];//实现4B->3B  int i=0;int index=0; //表示当前在密文中的下标 while(len--&&c[index]!='='){tmp_4[i]=base_table.find(c[index])&0x3f; //通过find函数 找到下标对应的值i++;index++;if(i==4){debase_3[0]=((tmp_4[0]&0x3f)<<2) + ((tmp_4[1]&0x30)>>4);debase_3[1]=((tmp_4[1]&0xf)<<4) + ((tmp_4[2]&0x3c)>>2);debase_3[2]=((tmp_4[2]&0x3)<<6) + (tmp_4[3]&0x3f);//注意位运算的优先级 for(int j =0;j<3;j++)m+=(char)debase_3[j];i=0;}}if(i){ // 如果i不为0 则表示 '=' 在4个字符中的下标 for(int j=i;j<4;j++)tmp_4[j]='\0';debase_3[0]=((tmp_4[0]&0x3f)<<2) + ((tmp_4[1]&0x30)>>4);debase_3[1]=((tmp_4[1]&0xf)<<4) + ((tmp_4[2]&0x3c)>>2); //最多转成两个字符for(int j=0;j<i-1;j++)  //j<i-1 比如 i=3时出现'=' 那么证明一个等号 故明文有两位 m+=debase_3[j];}return m;
}

实战中的魔改例子

1、通过异或还原表

具体步骤不在过多叙述,主要看到在循环体的索引后进行了一步异或,跟进查看表的内容。
确实,异或使base64表面目全飞。
dump出,接着跟0x76异或一次,发现是原始的base64表,正常base64解密即可。
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

2、通过移位产生表

附上实例:
对每一个转换后的6bit数 + 61 也就是表的ASCII码范围是61 + i (i 从 0 到 63),直接python写个脚本生成表,通过索引还原,再解密即可。

import base64
table=''
for i in range(64):table+=chr(i+61)
c='@BdxRTbRBbjIVf`PEyqe^\^\|cc|JRubaGLytHeRI@jgNegHU[Myy]=='
base='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
cc=''
for i in range(len(c)-2):cc+=base[table.find(c[i])]
cc+='=='
cipher=base64.b64decode(cc)

参考链接:
base64加密原理c++.
std::string使用总结.
为什么要使用Base64?.

RE-Base64编码分析相关推荐

  1. Html5 FileReader 对文件进行Base64编码

    以Base64进行编码的数据Url开始越来越广泛的被应用起来,原来做Base64转换要自己写一个小程序来转,其实Html5的FileReader的readAsDataURL方法读取出的数据就已经是Ba ...

  2. http传输html图片方式,http怎么样传输图片?二进制流还是base64编码

    面试官问本人http怎么传图片的,本人说二进制流  但他说图片是通过base64编码后传的 本人只是知道这种方法也可行 当时本人也不好得跟他争辩 回来后本人抓包分析后 觉得他说的有问题 .下面是本人用 ...

  3. base64编码 springboot_Spring Boot 中如何实现 HTTP 认证?

    松哥给最近连载的 Spring Security 系列也录制了视频教程,感兴趣的小伙伴请戳这里->Spring Boot+Vue+微人事视频教程(Spring Boot 第十章就是 Spring ...

  4. Base64编码运用与基本原理

    编码说白了就是按照一定规则对数据进行转换,工作原理有点类似于查字典,base64编码(叫base64的原因是因为其使用64个字符来对任意数据进行编码)可以用来将图片或者其他文件的二进制数据转换成字符串 ...

  5. token要加编码decode吗_彻底弄明白Base64 编码

    Base64 encoding/decoding常见于各种authentication和防盗链的实现当中.彻底搞懂它绝对提升团队troubleshooting的底气.我们从纯手工方式编码解码开始,然后 ...

  6. mysql 图片base64_关于图片的Base64编码

    什么是Base64编码 Base64编码是一种图片处理格式,通过特定的算法将图片编码成一长串字符串,在页面上显示的时候,可以用该字符串来代替图片的url属性. base64编码就是长得像下面这样子的代 ...

  7. 一文带你读懂base64编码

    hi,大家好,我是开发者FTD.相信很多同学在工作中,经常会用到Base64编码,那大家知道为什么会有Base64编码吗?我们为什么要使用它呢,它又是怎么实现的呢?下面就让我们来一起深入探究一下Bas ...

  8. Java、JS、OC、Flutter的Base64编码和解码

    题记 -- 执剑天涯,从你的点滴积累开始,所及之处,必精益求精,即是折腾每一天. ** 你可能需要 CSDN 网易云课堂教程 掘金 EDU学院教程 知乎 Flutter系列文章 本文章将描述在 Jav ...

  9. 消息(4)——WS附件传输,包体中的base64编码附件

    Soap包中可以存放数据的地方可以是soap头也可以是soap body部分.其中body部分是必须的,是重要的数据存放位置.Soap头中也可以放一些数据,例如Web服务中的安全中用户检测.例如: 如 ...

  10. base64 加密有空格 换行_[编码解码] Base64 编码换行和+号遍空格的处理

    Android自身带有Base64加密与解密的包,可以方便地加密密码方便传输. String base64Token = Base64.encodeToString(token.trim().getB ...

最新文章

  1. VS2010 + Qt5.3.2配置教程
  2. Mysql 将一张表的数据插入到另一张表中
  3. LeetCode每日一题 19. 删除链表的倒数第N个节点
  4. Ajax前后端对接---Springmvc
  5. 学习swing鼠标点击事件心得体会_西门子COMOS软件开发定制学习8-查询列表间的数据交互...
  6. 【转载】可能是把Docker的概念讲的最清楚的一篇文章
  7. vue在html中写style,vue开发之style(六)(CSS页面布局之样式、背景、文字)
  8. 计算机一级重点知识,计算机一级MSOffice考试重点:数制的基本概念
  9. maltab利用plot画图后更改线条颜色
  10. css属性~(积少成多)
  11. 微信小程序-强制手机端更新
  12. linux php adodb,【原创】Linux下php使用adodb对sql Server访问配置
  13. 台达DOP-B触摸屏通过MODBUS RTU通讯4台台达M变频器.含触摸屏程序,接线图和变频器参数设定
  14. 全功能开源的企业级安全主动攻击型蜜罐钓鱼系统 HFish,你很有必要部署一套!...
  15. java识别图片文字_java 实现图片的文字识别
  16. STM32——触摸屏实验-电阻型触摸屏-M4
  17. 移动端自动化测试实战(一)
  18. 首次用jwt做token
  19. 一分钟搞定最长公共子序列与最长公共子串的问题
  20. 《CCNA学习指南:数据中心(640-911)》——1.3 物理网络拓扑

热门文章

  1. bp神经网络数字识别matlab_pytorch神经网络实践(1): 安装与初次使用pytorch搭建神经网络实践手写数字识别教程
  2. 黑马程序员-android视频播放器
  3. gdiPlus 显示图片缩放不正确的可能解决方案
  4. IEEE Access 模板 图片编辑
  5. BAT代码表白实用详细操作
  6. 怎么在电脑上进行屏幕录像?电脑录屏的方法
  7. 【Pandas】实操手册
  8. Java常用算法-二分查找算法(两种方法实现)
  9. 三角形外心的坐标公式
  10. 离散数学11:图的着色