RSA算法
数学基础知识
互质关系
如果两个正整数,除了1以外,没有其他公因子,我们就称这两个数是互质关系
- 任意两个质数构成互质关系
- 一个数是质数,另一个数只要不是前者的倍数,两者就构成互质关系
- 1和任意一个自然数是都是互质关系
- p是大于1的整数,则p和p-1构成互质关系
- p是大于1的奇数,则p和p-2构成互质关系
欧拉函数
在小于等于n的正整数之中,能与n构成互质关系的数的个数
计算这个值的方法叫做欧拉函数,以φ(n)表示
-
如果n=1,则 φ(1) = 1 。因为1与任何数(包括自身)都构成互质关系
-
如果n是质数,则 φ(n)=n-1 。因为质数与小于它的每一个数,都构成互质关系
-
如果n是质数的某一个次方,即 n = p^k (p为质数,k为大于等于1的整数)
φ(p^k^) = p^k^ - p^k-1^
-
如果n可以分解成两个互质的整数之积,即
n = p1 × p2
则
φ(n) = φ(p1 × p2) = φ(p1) × φ(p2)
欧拉定理
如果两个正整数a和n互质,则n的欧拉函数 φ(n) 可以让下面的等式成立:
a^φ(n)^≡1(mod n)
费马小定理:
假设正整数a与质数p互质,因为质数p的φ§等于p-1,则欧拉定理可以写成
a^p-1^≡1(mod p)
模反元素
如果两个正整数a和n互质,那么一定可以找到整数b,使得 ab-1 被n整除,或者说ab被n除的余数是1。
ab≡1(mod n)
这时候b就叫做a的"模反元素"
RSA算法基本概念
-
RSA加密
密文 = 明文^E^modN
公钥 = (E,N)
-
RSA解密
明文 = 密文^D^modN
私钥 = (D,N)
公钥 | (E,N) |
私钥 | (D,N) |
密钥对 | (E,D,N) |
加密 | 密文 = 明文^E^modN |
解密 | 明文 = 密文^D^modN |
生成密钥对过程
-
随机找两个质数p和q,p和q越大越安全,计算他们的乘积
n=p*q
实际算法中p和q的乘积转化为二进制为1024位或2048位,位数越长,算法越难被破解
-
计算n的欧拉函数
L = φ(n)
φ(n)表示在小于等于n的正整数之中,与n构成互质关系的数的个数。
互质关系:互质是公约数只有1的两个整数。
φ(n) = φ(p*q) = φ§*φ(q) = (p-1)*(q-1)
欧拉函数特殊性质:
- 若m,n互质,φ(m*n) = φ(m)*φ(n)
- 若n为质数则,φ(n) = n-1
-
求E
E是随机选取的一个数,满足两个条件:1<E<L;E和L的最大公约数为1
-
求D
D必须满足
1
21 < D < L
E*D mod L = 1也就是满足乘法逆元E*D≡1(mod L)
D为E关于1模L的乘法逆元
求N | N= p*q ;p,q为质数 |
求L | L = (p-1)*(q-1) |
求E | 1<E<L,E与L互质 |
求D | 1 < D < L,E*D mod L = 1 |
Windows下yafu安装及使用
安装yafu
下载网址:yafu下载
使用yafu
- 进入yafu解压目录,打开cmd命令行
- 输入
yafu-x64
(即yafu64位文件名)
命令:factor(n)
—— n 为需要分解的大数
若n位数过长,将n值保存在文本文档里,最后一定要有换行符
1 | yafu-x64 "factor(@)" -batchfile test.txt |
其中test.txt
为保存需分解的大质数的文本文档
使用python来进行RSA加密解密
gmpy2库 安装 请参见 【linux笔记】
有了N求p、q可使用网址大质数分解 或者使用yafu
1 | import gmpy2 |
SM4算法
参考链接:欣仔带你零基础入门SM4加密算法
SM4算法简介
SM4是一个分组密码,明文和密文的长度是128位,秘钥的长度是128位。
将128位分成以32位为单位
SM4分步讲解
S盒处理
先进行S盒处理,s盒为特定数据
由于S盒只能处理两位十六进制数,也就是8位,所以处理32位时候采用4个s盒并列来进行加密
L变换
将S盒输出的32位(例如下图B)作为L变换的输入,
也就是L(B)返回B ^ (B<<<2) ^ (B<<<10) ^ (B<<<18) ^ (B<<<24)
轮函数
X~0~ X~1~ X~2~ X~3~ 为128位的明文分成的四个32位
SM4加密算法
轮秘钥rk生成
CTF中SM4算法的特征
-
S盒固定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19unsigned char TAO[16][16] =
{
{0xd6,0x90,0xe9,0xfe,0xcc,0xe1,0x3d,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x05},
{0x2b,0x67,0x9a,0x76,0x2a,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99},
{0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62},
{0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6},
{0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8},
{0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35},
{0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87},
{0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe7,0xa0,0xc4,0xc8,0x9e},
{0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1},
{0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3},
{0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f},
{0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51},
{0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8},
{0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0},
{0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84},
{0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48}
}; -
系统参数 FK 固定
1
unsigned long FK[4] = {0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc};
-
固定参数 CK 固定
1
2
3
4
5
6
7
8
9
10
11unsigned long CK[32] =
{
0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
};
使用python库对SM4算法进行解密
pysm4库 安装 请参见 【linux笔记】
标准128位加密
1 | >>> from pysm4 import encrypt, decrypt |
特殊情况参见pysm4安装文档
RC4算法
RC4算法简单讲述
- 生成S盒
开始时,S中元素的值被置为按升序从0到255,即S[0]=0,S[1]=1,…,S[255]=255。同时建立一个临时矢量T(长度与S相同)。如果密钥K的长度为256字节,则将K赋给T(K的长度为可能小于S的长度)。否则,若密钥长度为keylen字节,则将K的值赋给T的前keylen个元素,并循环重复用K的值赋给T剩下的元素,直到T的所有元素都被赋值。
- 打乱S盒
然后用T产生S的初始置换.从S[0]到S [255],对每个S[i],根据由T[i]确定的方案,将S[i]置换为S中的另一字节。
秘钥调度算法(KSA)
1 | void rc4_init(unsigned char *s, unsigned char *key, unsigned long Len) //初始化函数 |
- 矢量S一旦完成初始化,输入密钥就不再被使用。密钥流的生成是从S[0]到S[255],对每个s[i],根据当前S的值,将S[i]与S中的另一字节置换。当S[255]完成置换后,操作继续重复,最后进行异或运算
伪随机生成算法(PRGA)
1 | void rc4_crypt(unsigned char *s, unsigned char *Data, unsigned long Len) //加解密 |
RC4算法解密脚本(c语言)
1 | void rc4_init(unsigned char* s, unsigned char* key, unsigned long Len_k) //初始化函数 |
RC4算法加密解密脚本
1 | #define _CRT_SECURE_NO_WARNINGS |
MD5加密
MD5基本描述
MD5的输入输出如下
- 输入:任意长的消息,512比特长的分组。
- 输出:160比特的消息摘要。
有时候获得到的md5是16位的,其实那16位是32位md5的长度,是从32位md5值来的。是将32位md5去掉前八位,去掉后八位得到的。
MD5特征(MD5函数的初始化IV)
一般来说,可以通过函数的初始化来判断是不是MD5函数。一般来说,如果一个函数有如下四个初始化的变量,可以猜测该函数为MD5函数,因为这是MD5函数的初始化IV。
1 | var int h0 := 0x67452301 |
查询MD5的网站
tea系列
tea系列加解密脚本(c语言)
1 |
|
base64加解密
更多讲解请参见 【Base16,Base32,Base64编码详细学习】
base64加解密脚本(c语言)
1 |
|
AES算法
AES—CBC
加密时,明文首先与IV异或,然后将结果进行块加密,得到的输出就是密文,同时本次的输出密文作为下一个块加密的IV。
1 | int main() |