avatar

RE加密算法

RSA算法

数学基础知识

互质关系

如果两个正整数,除了1以外,没有其他公因子,我们就称这两个数是互质关系

  1. 任意两个质数构成互质关系
  2. 一个数是质数,另一个数只要不是前者的倍数,两者就构成互质关系
  3. 1和任意一个自然数是都是互质关系
  4. p是大于1的整数,则p和p-1构成互质关系
  5. p是大于1的奇数,则p和p-2构成互质关系

欧拉函数

在小于等于n的正整数之中,能与n构成互质关系的数的个数
计算这个值的方法叫做欧拉函数,以φ(n)表示

  1. 如果n=1,则 φ(1) = 1 。因为1与任何数(包括自身)都构成互质关系

  2. 如果n是质数,则 φ(n)=n-1 。因为质数与小于它的每一个数,都构成互质关系

  3. 如果n是质数的某一个次方,即 n = p^k (p为质数,k为大于等于1的整数)

    φ(p^k^) = p^k^ - p^k-1^

  4. 如果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算法基本概念

  1. RSA加密

    密文 = 明文^E^modN

    公钥 = (E,N)

  2. RSA解密

    明文 = 密文^D^modN

    私钥 = (D,N)

公钥 (E,N)
私钥 (D,N)
密钥对 (E,D,N)
加密 密文 = 明文^E^modN
解密 明文 = 密文^D^modN

生成密钥对过程

  1. 随机找两个质数p和q,p和q越大越安全,计算他们的乘积n=p*q

    实际算法中p和q的乘积转化为二进制为1024位或2048位,位数越长,算法越难被破解

  2. 计算n的欧拉函数 L = φ(n)

    φ(n)表示在小于等于n的正整数之中,与n构成互质关系的数的个数。

    互质关系:互质是公约数只有1的两个整数。

    φ(n) = φ(p*q) = φ§*φ(q) = (p-1)*(q-1)

    欧拉函数特殊性质:

    1. 若m,n互质,φ(m*n) = φ(m)*φ(n)
    2. 若n为质数则,φ(n) = n-1
  3. 求E

    E是随机选取的一个数,满足两个条件:1<E<L;E和L的最大公约数为1

  4. 求D

    D必须满足

    1
    2
    1 < 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

  1. 进入yafu解压目录,打开cmd命令行
  2. 输入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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import gmpy2
N = 103461035900816914121390101299049044413950405173712170434161686539878160984549
E = 65537
p = 282164587459512124844245113950593348271
q = 366669102002966856876605669837014229419
L = (p-1)*(q-1)
D = int(gmpy2.invert(E, L))
'''
gmpy2.invert()返回值类型为<class 'mpz'>
invert(x,y) 计算 x 关于1模 y 的乘法逆元
'''
enstr = 0xad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35
destr = gmpy2.powmod(enstr, D, N)
'''
gmpy2.powmod()返回值类型为<class 'mpz'>
gmpy2.powmod(x,y,z),计算x^y mod z 的值并返回
'''
flag0 = hex(destr)[2:] # flag0类型为str,存的是十六进制表示的字符串
flag1 = bytes.fromhex(flag0) # 将其从十六进制转换为byte类型(此时已解释成字符)
flag = str(flag1, 'utf-8') # 将byte类型转换为str类型
print(flag)

SM4算法

参考链接:欣仔带你零基础入门SM4加密算法

SM4算法简介

SM4是一个分组密码,明文和密文的长度是128位,秘钥的长度是128位。

将128位分成以32位为单位

SM4分步讲解

S盒处理

先进行S盒处理,s盒为特定数据

image-20200206195951088

由于S盒只能处理两位十六进制数,也就是8位,所以处理32位时候采用4个s盒并列来进行加密

image-20200206203037458

L变换

将S盒输出的32位(例如下图B)作为L变换的输入,

image-20200206204241175

image-20200206203443604

也就是L(B)返回B ^ (B<<<2) ^ (B<<<10) ^ (B<<<18) ^ (B<<<24)

轮函数

X~0~ X~1~ X~2~ X~3~ 为128位的明文分成的四个32位

轮函数

image-20200206212325570

SM4加密算法

image-20200206214523262

image-20200206214617744

轮秘钥rk生成

image-20200206221433180

image-20200206221532274

CTF中SM4算法的特征

  1. S盒固定

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    unsigned 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}
    };
  2. 系统参数 FK 固定

    1
    unsigned long FK[4] = {0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc};
  3. 固定参数 CK 固定

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    unsigned 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
2
3
4
5
6
7
8
9
10
11
12
>>> from pysm4 import encrypt, decrypt
# 明文
>>> clear_num = 0x0123456789abcdeffedcba9876543210
# 密钥
>>> mk = 0x0123456789abcdeffedcba9876543210
# 加密
>>> cipher_num = encrypt(clear_num, mk)
>>> hex(cipher_num)[2:].replace('L', '')
'681edf34d206965e86b3e94f536e4246'
# 解密
>>> clear_num == decrypt(cipher_num, mk)
True

特殊情况参见pysm4安装文档

此链接仅作保存|没有验证过

RC4算法

RC4算法简单讲述

  1. 生成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的所有元素都被赋值。

  1. 打乱S盒

然后用T产生S的初始置换.从S[0]到S [255],对每个S[i],根据由T[i]确定的方案,将S[i]置换为S中的另一字节。

秘钥调度算法(KSA)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void rc4_init(unsigned char *s, unsigned char *key, unsigned long Len) //初始化函数
{
int i =0, j = 0;
char k[256] = {0};
unsigned char tmp = 0;
for (i=0;i<256;i++) {
s[i] = i;
k[i] = key[i%Len];
}
for (i=0; i<256; i++) {
j=(j+s[i]+k[i])%256;
tmp = s[i];
s[i] = s[j]; //交换s[i]和s[j]
s[j] = tmp;
}
}
  1. 矢量S一旦完成初始化,输入密钥就不再被使用。密钥流的生成是从S[0]到S[255],对每个s[i],根据当前S的值,将S[i]与S中的另一字节置换。当S[255]完成置换后,操作继续重复,最后进行异或运算

伪随机生成算法(PRGA)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void rc4_crypt(unsigned char *s, unsigned char *Data, unsigned long Len) //加解密
{
int i = 0, j = 0, t = 0;
unsigned long k = 0;
unsigned char tmp;
for(k=0;k<Len;k++) {
i=(i+1)%256;
j=(j+s[i])%256;
tmp = s[i];
s[i] = s[j]; //交换s[x]和s[y]
s[j] = tmp;
t=(s[i]+s[j])%256;
Data[k] ^= s[t];
}
}

RC4算法解密脚本(c语言)

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
void rc4_init(unsigned char* s, unsigned char* key, unsigned long Len_k) //初始化函数
{
int i = 0, j = 0;
char k[256] = { 0 };
unsigned char tmp = 0;
for (i = 0; i < 256; i++) {
s[i] = i;
k[i] = key[i % Len_k];
}
for (i = 0; i < 256; i++) {
j = (j + s[i] + k[i]) % 256;
tmp = s[i];
s[i] = s[j]; //交换s[i]和s[j]
s[j] = tmp;
}
}

/*
RC4加解密函数
unsigned char* Data 加解密的数据
unsigned long Len_D 加解密数据的长度
unsigned char* key 密钥
unsigned long Len_k 密钥长度
*/
void rc4_crypt(unsigned char* Data, unsigned long Len_D, unsigned char* key, unsigned long Len_k) //加解密
{
unsigned char s[256];
rc4_init(s, key, Len_k);
int i = 0, j = 0, t = 0;
unsigned long k = 0;
unsigned char tmp;
for (k = 0; k < Len_D; k++) {
i = (i + 1) % 256;
j = (j + s[i]) % 256;
tmp = s[i];
s[i] = s[j]; //交换s[x]和s[y]
s[j] = tmp;
t = (s[i] + s[j]) % 256;
Data[k] ^= s[t];
}
}

RC4算法加密解密脚本

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
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

using namespace std;

struct rc4_state {
int x, y, m[256];
};

void rc4_setup(struct rc4_state* s, unsigned char* key, int length);
void rc4_crypt(struct rc4_state* s, unsigned char* data, int length);

void rc4_setup(struct rc4_state* s, unsigned char* key, int length) {
int i, j, k, * m, a;

s->x = 0;
s->y = 0;
m = s->m;

for (i = 0; i < 256; i++) {
m[i] = i;
}

j = k = 0;

for (i = 0; i < 256; i++)
{
a = m[i];
j = (unsigned char)(j + a + key[k]);
m[i] = m[j]; m[j] = a;
if (++k >= length) k = 0;
}
}

void rc4_crypt(struct rc4_state* s, unsigned char* data, int length) {
int i, x, y, * m, a, b;
x = s->x;
y = s->y;
m = s->m;
for (i = 0; i < length; i++) {
x = (unsigned char)(x + 1); a = m[x];
y = (unsigned char)(y + a);
m[x] = b = m[y];
m[y] = a;
data[i] ^= m[(unsigned char)(a + b)];
}
s->x = x;
s->y = y;
}

int main() {
const char* key = "12345678";
int len = 8;

char data[512];
memset(data, 0, sizeof(data));
memcpy(data, "helloworld", 11);

struct rc4_state* s;
s = (struct rc4_state*) malloc(sizeof(struct rc4_state));

//加密
rc4_setup(s, (unsigned char*)key, strlen(key));
rc4_crypt(s, (unsigned char*)data, strlen(data));

//从0-len(data)输出即可,不过可能会有\x00,人工判断长度吧
printf("%s\n", data);


//解密
rc4_setup(s, (unsigned char*)key, strlen(key));
rc4_crypt(s, (unsigned char*)data, strlen(data));
printf("%s\n", data);

return 0;
}

MD5加密

MD5基本描述

MD5的输入输出如下

  • 输入:任意长的消息,512比特长的分组。
  • 输出:160比特的消息摘要。

有时候获得到的md5是16位的,其实那16位是32位md5的长度,是从32位md5值来的。是将32位md5去掉前八位,去掉后八位得到的。

MD5特征(MD5函数的初始化IV)

一般来说,可以通过函数的初始化来判断是不是MD5函数。一般来说,如果一个函数有如下四个初始化的变量,可以猜测该函数为MD5函数,因为这是MD5函数的初始化IV。

1
2
3
4
var int h0 := 0x67452301
var int h1 := 0xEFCDAB89
var int h2 := 0x98BADCFE
var int h3 := 0x10325476

查询MD5的网站

tea系列

tea系列加解密脚本(c语言)

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
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#define tea_DELTA 0x9e3779b9
/*
tea加密函数
32轮加密,请根据需要更改
uint32_t* origin 为要加密的数据是两个32位无符号整数
uint32_t* key 为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
*/
void tea_encode(uint32_t* origin, uint32_t* key) {
uint32_t v0 = origin[0], v1 = origin[1], sum = 0, i; /* set up */
uint32_t delta = 0x9e3779b9; /* a key schedule constant */
uint32_t k0 = key[0], k1 = key[1], k2 = key[2], k3 = key[3]; /* cache key */
for (i = 0; i < 32; i++) { /* basic cycle start */
sum += delta;
v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
} /* end cycle */
origin[0] = v0; origin[1] = v1;
}
/*
tea解密函数
32轮解密,请根据需要更改
uint32_t* origin 为要加密的数据是两个32位无符号整数
uint32_t* key 为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
*/
void tea_decode(uint32_t* origin, uint32_t* key) {
uint32_t v0 = origin[0], v1 = origin[1], i; /* set up */
uint32_t delta = 0x9e3779b9,sum = delta << 5; //32轮运算,所以是2的5次方;16轮运算,所以是2的4次方;8轮运算,所以是2的3次方/* a key schedule constant */
uint32_t k0 = key[0], k1 = key[1], k2 = key[2], k3 = key[3]; /* cache key */
for (i = 0; i < 32; i++) { /* basic cycle start */
v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
sum -= delta;
} /* end cycle */
origin[0] = v0; origin[1] = v1;
}



/*
xtea加密函数
num_rounds 加密轮数
uint32_t* origin 为要加密的数据是两个32位无符号整数
uint32_t* k 为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
*/
void xtea_encode(unsigned int num_rounds, uint32_t origin[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0 = origin[0], v1 = origin[1], sum = 0, delta = 0x9E3779B9;
for (i = 0; i < num_rounds; i++) {
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
sum += delta;
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
}
origin[0] = v0; origin[1] = v1;
}
/*
xtea解密函数
num_rounds 加密轮数
uint32_t* origin 为要加密的数据是两个32位无符号整数
uint32_t* k 为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
*/
void xtea_decode(unsigned int num_rounds, uint32_t origin[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0 = origin[0], v1 = origin[1], delta = 0x9E3779B9, sum = delta * num_rounds;
for (i = 0; i < num_rounds; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
}
origin[0] = v0; origin[1] = v1;
}



// xxtea加密解密
#if 0
int main()//例子
{
uint32_t v[2] = { 1,2 };
uint32_t const k[4] = { 2,2,3,4 };
int n = 2; //n的绝对值表示v的长度,取正表示加密,取负表示解密
// v为要加密的数据是两个32位无符号整数
// k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
printf("加密前原始数据:%u %u\n", v[0], v[1]);
xxtea(v, n, k);
printf("加密后的数据:%u %u\n", v[0], v[1]);
xxtea(v, -n, k);
printf("解密后的数据:%u %u\n", v[0], v[1]);
return 0;
}
#endif
#define xxtea_MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
/*
origin 为要加密的数据是两个32位无符号整数(若加密字符串先转换为16进制整数)
n 的绝对值表示v的长度(即有几个32位整数),取正表示加密,取负表示解密
key 为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
*/
void xxtea(uint32_t* origin, int n, uint32_t const key[4])
{
uint32_t y, z, sum;
unsigned p, rounds, e;
if (n > 1) /* Coding Part */
{
rounds = 6 + 52 / n;
sum = 0;
z = origin[n - 1];
do
{
sum += tea_DELTA;
e = (sum >> 2) & 3;
for (p = 0; p < n - 1; p++)
{
y = origin[p + 1];
z = origin[p] += xxtea_MX;
}
y = origin[0];
z = origin[n - 1] += xxtea_MX;
} while (--rounds);
}
else if (n < -1) /* Decoding Part */
{
n = -n;
rounds = 6 + 52 / n;
sum = rounds * tea_DELTA;
y = origin[0];
do
{
e = (sum >> 2) & 3;
for (p = n - 1; p > 0; p--)
{
z = origin[p - 1];
y = origin[p] -= xxtea_MX;
}
z = origin[n - 1];
y = origin[0] -= xxtea_MX;
sum -= tea_DELTA;
} while (--rounds);
}
}

base64加解密

更多讲解请参见 【Base16,Base32,Base64编码详细学习】

base64加解密脚本(c语言)

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
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144

/*
base64加密
const unsigned char* src 需要加密的数组
unsigned char* dst 加密之后存储的数组
*/
int base64_encode(const unsigned char* src, unsigned char* dst)
{

size_t len = strlen((const char*)src);
static unsigned char base64char[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

while (len > 2) {
*dst++ = base64char[src[0] >> 2 & 0x3f];
*dst++ = base64char[(src[0] & 0x3) << 4 | src[1] >> 4 & 0xf];
*dst++ = base64char[(src[1] & 0xf) << 2 | src[2] >> 6 & 0x3];
*dst++ = base64char[src[2] & 0x3f];
len -= 3;
src += 3;
}

if (len) {
*dst++ = base64char[src[0] >> 2 & 0x3f];
if (len > 1) {
*dst++ = base64char[((src[0] & 0x3) << 4) | ((src[1] >> 4) & 0xf)];
*dst++ = base64char[(src[1] & 0xf) << 2];
}
else {
*dst++ = base64char[(src[0] & 0x3) << 4];
*dst++ = '=';
}
*dst++ = '=';
}

*dst = 0;
return 0;
}

/*
base64解密
const unsigned char* src 需要解密的字符
unsigned char* dst 解密之后存储的数组
*/
int base64_decode(const unsigned char* src, unsigned char* dst)
{
static char base64char[] = {
-1 , -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1 , -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1 , -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
-1 , 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, -1, -1, -1, -1, 63,
-1 , 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, -1, -1, -1, -1, -1,
};

int i;
size_t len = strlen((const char*)src);

for (i = 0; i < len; i++) {
if (src[i] == -1) {
return 1; //unexpected characters
}
else if (src[i] == '=') {
len = i;
}
}

if (len % 4 == 1) {
return 2;
}

while (len > 3) {
*dst++ = (unsigned char)(base64char[src[0]] << 2) | (base64char[src[1]] >> 4 & 0x3);
*dst++ = (unsigned char)(base64char[src[1]] << 4) | (base64char[src[2]] >> 2 & 0xf);
*dst++ = (unsigned char)(base64char[src[2]] << 6) | (base64char[src[3]]);

src += 4;
len -= 4;
}

if (len) {
if (len > 1) {
*dst++ = (base64char[src[0]] << 2) | (base64char[src[1]] >> 4 & 0x3);
}

if (len > 2) {
*dst++ = (base64char[src[1]] << 4) | (base64char[src[2]] >> 2 & 0xf);
}

}
*dst = 0;
return 0;
}

/*
base64自定义字符表加密
char* src 存放待加密字符串的数组
char* dst 存放加密后字符串的数组
char* mytable 自定义字符表
*/
void base64_myen(char* src, char*dst, char* mytable)
{
base64_encode((const unsigned char*)src,(unsigned char*)dst);
int i, j;
char base64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int len_s = strlen(dst);
for (i = 0; i < len_s; i++)
{
for (j = 0; j < 65; j++)
{
if (dst[i] == base64_table[j])
{
dst[i] = mytable[j];
break;
}
}
}
}

/*
base64自定义字符表解密
char* src 存放待解密字符串的数组
char* dst 存放解密后字符串的数组
char* mytable 自定义字符表
*/
void base64_myde(char* src, char* dst, char* mytable)
{
int i, j;
char base64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int len_s = strlen(src);
for (i = 0; i < len_s; i++)
{
for (j = 0; j < 65; j++)
{
if (src[i] == mytable[j])
{
src[i] = base64_table[j];
break;
}
}
}
base64_decode((const unsigned char*)src, (unsigned char*)dst);
}

AES算法

AES—CBC

加密时,明文首先与IV异或,然后将结果进行块加密,得到的输出就是密文,同时本次的输出密文作为下一个块加密的IV。

image-20200207231215446

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
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
52
53
54
int main()
{
uint8_t key[16] = {
0x01, 0x02, 0x03, 0x04, 0x0a, 0x0b, 0x0c, 0x0d, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
};
uint8_t iv[16] = {
0xa, 0xb, 0xc, 0xd, 0x1, 0x2, 0x3, 0x3, 0xa, 0xa, 0xa, 0xa, 0xf, 0xf, 0xf, 0xf
};
uint8_t* text = "hello aes_cbc encryption!";

printf("密钥:");
for (int i = 0; i < 16; ++i){
if (i%4 == 0 && i != 0)
printf(" ");
if (i % 16 == 0 && i != 0)
printf("\n");
printf("%02x ", key[i]);
}
printf("\n");
printf("明文:%s\n\n", text);

set_iv(iv);
//--------------------------aes cbc encrypt--------------------------------------
cypher_t* plain = (cypher_t*)malloc(sizeof(uint8_t) + strlen(text));
plain->len_data = strlen(text);
memcpy(plain->data, text, plain->len_data);
cypher_t* cypher = aes_cbc_encrypt(key, plain);
puts("密文:");
for (int i = 0; i < cypher->len_data; ++i){
if (i%4 == 0 && i != 0)
printf(" ");
if (i % 16 == 0 && i != 0)
printf("\n");
printf("%02x ", cypher->data[i]);

}
printf("\n\n");
free(plain);
//--------------------------aes cbc decrypt--------------------------------------
cypher_t* decrypted_plain = aes_cbc_decrypt(key, cypher);
puts("解密之后:");
for (int i = 0; i < decrypted_plain->len_data; ++i){
if (i%4 == 0 && i != 0)
printf(" ");
if (i % 16 == 0 && i != 0)
printf("\n");
printf("%02x ", decrypted_plain->data[i]);
}
printf("\n\n");
printf("解密之后的明文字符串输出:\n%s", decrypted_plain);
printf("\n\n");
free(decrypted_plain);
return 0;
}
Author: L0x1c
Link: https://l0x1c.github.io/2020/04/27/2020-02-02/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付寶
    支付寶