Reverse常见算法
1byte->2**n bytes
- 非对称加密:RSA ECC SM2 SM9
- 哈希:MD5 SHA SM3
- base58(整除)
1byte->n bytes
- 分组:SM1 SM4 SM7
- base16,32,64,85
1byte->1 byte
- 替换密码
- RC4 ZUC
base64
核心:三转四


补充一下我对倒数第四行的的困惑及解释:字母和3进行与操作只保留字母的二进制最后两位,左移4相当于给低四位加0,一共是六位;后半部分直接右移4,相当于只剩4位,两数取或运算后面的数虽然只有4位,但前面可以补0,且一个数跟0进行或运算取决于它自身,所以一共是6位
有时候会是下面的形式,主要一下子没看出来,记录一下。发现>>2和&0x3f还是在的,另外一些用位操作代替了,且对字符串的长度根据%3的余数做了分类

也有这种位运算之后全是&0x3f的

%3和=告诉我下面的也是base64

RC4
1.先初始化状态向量S(用来作为密钥流生成的种子1)
2.初始密钥key(由用户输入),长度任意,如果输入长度小于256个字节,则进行循环,直到填满k,有时候k用t来表示
3.开始对状态向量S进行置换操作(用来打乱初始种子1)
KSA

4.生成密钥
PGRA

rc4也可以&255(0xff)

在rc4中,key通常为初始化函数的中间参数,可以快速找到
1 |
|
%128的魔改本质上就是8位二进制数组成的密钥变为7位
TEA
常规
一种对称算法,它使用64位明文(一组密文,232位)和128位密钥(一般是432位)进行加解密
TEA系列算法中均使用一个DELTA常数,但DELTA的值对算法并无什么影响,只是为了避免不良的取值,推荐DELTA的值十六进制值为0x9e3779B9,用于保证每一轮加密都不相同
标准加密流程
- 将明文按64位分组,将每个分组视为一个64位的二进制数,记为V
- 将128位的密钥分成4个32位的子密钥,分别记为K0、K1、K2、K3
- 将明文分组V分为两个32位的部分,分别记为V0和V1
- 设定一个32位的常数delta
- TEA算法的加密过程包括32轮迭代,每一轮的加密过程如下:
a. 首先,累加器sum被初始化为0
b. 接着,将delta值加到sum中。delta是一个常数,其值通常为0x9e3779b9,用于增加加密的随机性
c. 然后,将V1左移4位,加上K0,再异或上(V1+sum)和(V1右移5位+K1)的值。得到的结果作为V0的新值
d. 接下来,将V0左移4位,加上K2,再异或上(V0+sum)和(V0右移5位+K3)的值。得到的结果作为V1的新值
e. 重复上述步骤32次,即完成一轮迭代。在每一轮迭代中,V0和V1的值都会被更新,其中V1的更新依赖V0,而V0的更新依赖于V1
- 经过32轮迭代后,得到加密后的密文,记为C0和C1
- 将C0和C1按顺序连接起来,得到64位的密文
算法注意点
key一般为加密函数第二个参数,sum-=0x61c88647和sum+=0x9e3779b9是等价的
循环里的l和r一般用v0和v1,这样不容易弄混
1 |
|
有些时候伪代码*4但实际上并不需要,因为这时的key是一个字节

注意v0和v1到底是int还是unsigned int

有多步操作的时候一定要注意写for循环的时候也要逆向,下面每次循环都要进行异或,自然得从后往前逆
1 |
|
tea算法会有很多魔改的地方,比如循环次数,算法中多异或几个数,下面在tea的前后还实现了交换

如果算法里面异或i的话里面的循环也要逆着写

解密脚本
由于涉及内存指针等问题,大部分用c写
1 |
|
tea加密的另一种模式
1 |
|
XTEA
从做题角度来说差别不大
XXTEA
相比xtea与tea,xxtea的复杂度更上了一层,subkey的方式变为已进行的轮数的最后两位与delta叠加的最后两位相异或,delta迭代与tea相同,常见是9轮循环,循环里面先q再p,q就是循环的次数,为6+52/(n+1)
1 |
|
有些没6+52/(n+1),但还是有其他特征,而且delta也很明显

下面是运行脚本
1 |
|
AES
参考链接: https://zhuanlan.zhihu.com/p/78913397
算法
AES算法主要有四种操作处理,分别是密钥加法层、字节代换层、行位移层、列混淆层。而明文x和密钥k都是由16个字节组成的数据
AES算法在处理的轮数上只有最后一轮操作与前面的轮处理上有些许不同,在轮处理开始前还单独进行了一次轮密钥加的处理。在处理轮数上,我们只考虑128位密钥的10轮处理

字节代换
S_box表是通过某种方法计算出来的。S_box表是一个拥有256个字节元素的数组,可以将其定义为一维数组,也可以将其定义为16×16的二维数组,如果将其定义为二维数组,读取S_box数据的方法就是要将输入数据的每个字节的高四位作为第一个下标,低四位作为第二个下标,从s盒中取出并赋给字符
s盒和逆s盒
1 |
|

特征值:>>4 &0xF
行位移
只在4×4矩阵的行间进行操作,每行4字节的数据。在加密时,保持矩阵的第一行不变,第二行向左移一个字节、第三行向左移2个字节、第四行向左移3个字节


特征值:三个>>和<<
也可以这样,这个真有点抽象


列混淆
在加密的正向列混淆中,我们要将输入的4·4矩阵左乘一个给定的4·4矩阵。而它们之间的加法、乘法都在扩展域GF(2^8)中进行,所以也就可以将这一个步骤分成两个部分进行讲解
1 |
|

轮密钥加
在密钥加法层中有两个输入的参数,分别是明文和子密钥k,而且这两个输入都是128位的。在%2的扩展域中加减法与异或运算等价,所以这里只需异或

密钥生成
子密钥的生成是以列为单位进行的,一列是32Bit,四列组成子密钥共128Bit。生成子密钥的数量比AES算法的轮数多一个,因为第一个密钥加法层进行密钥漂白时也需要子密钥。密钥漂白是指在AES的输入盒输出中都使用的子密钥的XOR加法。子密钥在图中都存储在W[0]、W[1]…W[43]的扩展密钥数组之中
k1-k16表示原始密钥对应的字节,而图中子密钥k0与原始子密钥相同。在生成的扩展密钥中W的下标如果是4的倍数时(从零开始)需要对异或的参数进行G函数处理
扩展密钥生成有关公式如下
1 |
|

T函数实现较复杂

填充
几种典型的填充方式:
NoPadding: 不做任何填充,但是要求明文必须是16字节的整数倍
PKCS5Padding(默认): 如果明文块少于16个字节,在明文块末尾补足相应数量的字符,且每个字节的值等于缺少的字符数。 比如明文:{1,2,3,4,5,a,b,c,d,e},缺少6个字节,则补全为{1,2,3,4,5,a,b,c,d,e,6,6,6,6,6,6 }
ISO10126Padding:如果明文块少于16个字节(128bit),在明文块末尾补足相应数量的字节,最后一个字符值等于缺少的字符数,其他字符填充随机数。比如明文:{1,2,3,4,5,a,b,c,d,e},缺少6个字节,则可能补全为{1,2,3,4,5,a,b,c,d,e,5,c,3,G,$,6}
PKCS7Padding原理与PKCS5Padding相似,区别是PKCS5Padding的blocksize为8字节,而PKCS7Padding的blocksize可以为1到255字节
模式
AES的工作模式,体现在把明文块加密成密文块的处理过程中。AES加密算法提供了五种不同的工作模式:CBC,ECB,CTR,CFB,OFB

适合加密随机数据

适合软件加密:CFB,OFB,CTR
代码
标准aes
1 |
|
这是修改s盒的代码,密文只能16位一组解密,密文按顺序提取unspaced即可
1 |
|
DES
对称密码,DES使用64位的密钥和64位的明文块进行加密。DES算法的分组大小是64位,因此,如果需要加密的明文长度不足64位,需要进行填充;如果明文长度超过64位,则需要使用分组模式进行分组加密
识别主要靠常量
初始置换(IP置换)
将输入的64位明文块进行置换和重新排列,生成新的64位数据块
目的:增加加密的混乱程度,使明文中的每一位都能够对后面的加密过程产生影响,提高加密强度
我们将把64位的顺序按下表中规定的顺序放置,图中的数字是在64位明文中每个比特的索引位置


加密轮次
初始置换完成后,明文被划分成了相同长度(32位)的左右两部分,记作L0,R0。接下来就会进行16个轮次的加密
从单独一个轮次来看,首先把目光聚焦在R0这里。右半部分R0会作为下一轮次的左半部分L1的输入。其次,R0会补位到48位和本轮次生成的48位K0输入到F轮函数中去。F函数的输出结果为32位,结果F(R0,K0)会和L0进行异或运算作为下一轮次右半部分R1的输入

以此类推,重复16轮运算

拓展R到48位
将32位的R0右半部分进行扩展,得到一个48位的数据块。同样的,数据拓展也是根据一个固定的置换表。红框中就是我们要补位的数据

由此可见,扩展过程的每一位都是根据上述的置换表从输入的32位数据块中提取出来的。原始数据的第32位被补充到了新增列的第一个,第5位被补充到了第二个新增列的第一个,以此类推
子密钥k的生成
DES算法采用了每轮子密钥生成的方式来增加密钥的复杂性和安全性。每轮子密钥都是由主密钥(64位)通过密钥调度算法(Key Schedule Algorithm)生成的。DES算法的密钥调度算法可以将64位的主密钥分成16个子密钥,每个子密钥48位,用于每轮加密中与输入数据进行异或运算
通过子密钥生成的流程图来看下整个过程

主密钥,下面56位是已经删除以8为倍数的奇偶校验位

异或
当前轮次的子密钥Ki(在上面56位的基础上删除特定的8位,得到48位)与拓展的48位Ri进行异或运算。运算结果会作为接下来S盒替换的输入
S盒替换
用于将上一轮异或运算的48位结果映射到32位输出中去
6位变4位,首尾两位作为行标,中间四位作为列标,去不同的S盒对应一个小于16的数,再转化为4位二进制数
P盒代换

P盒代换将S盒替换的32位输出作为输入,经过上述固定的代换表进行代换后即为最后F轮函数的结果
逆置换



3DES
3DES顾名思义,就i是使用DES加密3次,使用3个密钥进行加解密

SM4
常数0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc
分组密码,分组长度128位,密钥长度128位,32轮迭代和一次反序变换,输入4字(16字节,换算方法是密码算法特有的)
分为密钥拓展和加/解密两个模块,下图是 SM4 的加解密(左)和密钥拓展(右)的流程图

1 |
|
加解密代码
1 |
|
MD5
[https://zhuanlan.zhihu.com/p/115270932#:~:text=C%E8%AF%AD%E8%A8%80%E5%AE%9E%E7%8E%B0%20%E4%BB%A5%E4%B8%8B%E4%BB%A3%E7%A0%81%E6%A0%B9%E6%8D%AE%E5%8F%82%E8%80%83%E6%96%87%E7%8C%AE%E4%BF%AE%E6%94%B9%E3%80%81%E6%B3%A8%E9%87%8A%E8%80%8C%E6%9D%A5%EF%BC%8C%E6%AF%95%E7%AB%9FMD5%E7%AE%97%E6%B3%95%E4%B8%8D%E6%98%AF%E6%88%91%E5%8E%9F%E5%88%9B%E7%9A%84%E3%80%82%20%2F%2A,%E5%87%BD%E6%95%B0%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E%EF%BC%9A%20%E5%85%88%E8%B0%83%E7%94%A8MD5Init%E5%88%9D%E5%A7%8B%E5%8C%96%E4%B8%80%E4%B8%AAMD5_CTX%E7%B1%BB%E5%9E%8B%E7%BB%93%E6%9E%84%E4%BD%93%EF%BC%8C%E5%86%8D%E4%BD%BF%E7%94%A8MD5Update%E8%AE%A1%E7%AE%97MD5%E7%A0%81%EF%BC%8C%E6%9C%80%E5%90%8E%E8%B0%83%E7%94%A8MD5Final%E8%8E%B7%E5%8F%96%20%E4%BD%BF%E7%94%A8%E7%A4%BA%E4%BE%8B%E8%A7%81%E6%9C%80%E4%B8%8B%E9%9D%A2%E7%9A%84main%E5%87%BD%E6%95%B0%E3%80%82](https://zhuanlan.zhihu.com/p/115270932#:~:text=C语言实现 以下代码根据参考文献修改、注释而来,毕竟MD5算法不是我原创的。 %2F*,函数使用说明: 先调用MD5Init初始化一个MD5_CTX类型结构体,再使用MD5Update计算MD5码,最后调用MD5Final获取 使用示例见最下面的main函数。)
MD5加密的函数大致如下:
MD5_CTX md5c;(结构体)
MD5Init(&md5c);
MD5UpdateString(&md5c,plain)
MD5Final(digest,&md5c);
数据填充
MD5算法的第二步“分组循环变换”是以512位为一个分组进行处理的。因此,需要把数据填充成长度为512位的倍数。具体填充步骤如下:
1、先填充一个“1”,后面加上k个“0”。其中k是满足(n+1+k) mod 512 = 448的最小正整数。
2、追加64位的数据长度(bit为单位,小端序存放)
填充完的数据大概长这样:

分组循环变换
其中,MD5Init会初始化四个称作MD5链接变量的整形参数。因此如果看到这4个常数0x67452301、0xefcdab89、0x98badcfe、0x10325476
,就应该是MD5算法了。MD5Init函数代码如下:
1 |
|
十进制表示如下,int最大是0x7fffffff,所以第2个和第3个为负数

然后将填充完成后的数据划分成一个个512位的分组,依次进入循环变换。A、B、C、D也参与到循环变换中。数据分组进去变换的时候,大概走这么个流程:

循环变换是整个MD5算法最核心,也是最复杂的部分。一个512位分组的数据被进一步划分为16个32位的子分组,对每个子分组进行下图所示的变换:

上面只是画出了一个子分组进行的变换。下面对图中的元素进行说明:
1.图中的F函数代表一次由位运算构成的非线性变换,每一轮循环变换用到的F函数不一样
2.常数AC的值在每一次变换中都不一样
3.左移位数S有规律地周期性变化
数据的16个子分组都参与到上图所示的变换,顺序不定。当16个子分组处理完成时,我们就说完成了一轮循环变换。MD5的一个数据分组一共需要进行四轮的循环变换。将四轮循环变换后得到的A、B、C、D的值分别和原来的值相加,就是A、B、C、D进行循环变换后的结果

拼接输出
将经过若干次循环变换后的A、B、C、D以十六进制的形式拼接起来,就是MD5码

这里是加密函数,而且也能看到hash[]

还有可能的特征

完整代码
1 |
|
BlowFish
是对称加密,是用来替代DES算法出现的,是 将一个数 拆分为 左右各32位然后 左边进行 ^ key_pbox 当作下一次循环的右边。右边 则是 右边 ^ F(左边)下次当作循环的左边
常量

常见的前几位PBox

密钥扩展
循环轮数先是18,后是256




数据加密

16轮循环,里面有交换操作

sha1
主循环4轮,每轮20次操作
有两组常量,分别对应k数组和MD buffer



1 |
|
祖冲之(ZUC)
序列密码,参考加解密脚本,需要已知key和iv
1 |
|
base58
基本思想:常⽤的字节码(256进制)转换成Base58,相当于将256进制转换成58进制
经典脚本,表的长度是61,1-9+大小写字母,一般会多次出现58

也有这样的

编码过程是:
\1. 将要转换的数据转换为字节数组
\2. 计算前置字节码是0的个数,因为0没必要参与转换,其结果是0。
\3. 将256进制转换为10进制
\4. 将10进制转换为58进制。
\5. 得到⼀个58进制的数组,将第⼆步0的个数添加到该数组末尾。n个0就添加n个0到数组末尾。
\6. 反转整个数组。
\7. 查表,将base58编码转换成字符。
这⾥的第3步如果转换的字节数组很⻓,那么以256为底数的指数将会⾮常庞⼤,需要使⽤⼤数,但实际上可以优化算法,没必要⼀次性将整个原始数组全部转换为10进制后才转换为58进制,可采取逐个转换为58进制的策略来进⾏,这样可以避免使⽤⼤整数,从⽽提⾼运算效率。




base58不需要key也能解出来


斐波那契数列
1 |
|
IDEA
国际数据加密算法
IDEA是块加密,与DES一样,IDEA也处理64位明文块,但是其密钥有128位,IDEA也用扩展与混淆进行加密



能看到0xffff,还有65537,还有加,异或的运算
1 |
|