学习报告(三到四周)

runwu2204 Lv6

学习报告(三到四周)

base16

可通过位运算(高效率)进行加密

基本已经知道其加密模式

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
#include<stdio.h>
char table[] = { "0123456789ABCDEF" };//字典
unsigned char r( char m)//一个字符将被加密为两个字符可分为左右
{
unsigned char a;
a=m<<4;
return a >> 4;
}
unsigned char l(char n)
{
unsigned char a;
a = n;
return (a>> 4);
}
unsigned char check( char a, char* b)
{
unsigned char c;//将char转为无符号的
for (c = 0; c <= 15; c++)
{
if (a == *(b + c))//检索字典寻找其四位对应值
{
return c;
}
}
return -1;
}
int main()
{
int flag, a, b, c, f;
printf("选择模式加密0/解密1:");
scanf("%d", &flag);
getchar();
if (flag == 0)
{
{
char yuan[100], jia[200];
printf("请输入待加密的字符:");
fgets(yuan,100,stdin);
for (a = 0; 1; a++)
{
if (yuan[a] == '\0')
{
break;
}
}
for (b = 0, f = 0; b < (2 * a); b += 2, f++)
{
jia[b] = table[l(yuan[f])];
jia[b + 1] = table[r(yuan[f])];
}
jia[2 * a] = '\0';
puts(jia);
}
}
else if (flag == 1)
{

char jiami[100], jiemi[50], e;
printf("请输入待解密的字符:");
fgets(jiami,100,stdin);
for (a = 0; 1; a++)
{
if (jiami[a] == '\n')
{
jiami[a] = '\0';
break;
}
}
for (b = 0, c = 0; b < a; b += 2, c++)
{

jiemi[c] = ((check(jiami[b], table) << 4) + check(jiami[b + 1], table));
}
jiemi[(a) / 2 -1] = '\0';
puts(jiemi);
}
else
printf("输入错误");
return 0;
}

base64

与base16类似都可以通过位运算进行加密

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
#include<stdio.h>
#include<stdlib.h>
char zidian[]={"ABCDEFGHIJKMLNOPQRSTUVWXYZabcdefghijkmlnopqrstuvwxyz0123456789+/"};//字典
void base64(char *jiami,int n,char *jiemi)//加密操作
{
unsigned char a;//vsc中char有符号
int b,c;
if(n%3==0)//每三个字符生成四个字符的密文,此处判断是否满足能被三整除以判断是否需要补位
{
for(b=0,c=0;b<(n-(n%3));c+=4,b+=3)//这几处位运算分开是因为位运算特性:运算结束后补0
{
a=jiami[b]>>2;//取char型的高6位
jiemi[c]=zidian[a];
a=jiami[b]<<6;
jiemi[c+1]=zidian[(a>>2)+(jiami[b+1]>>4)];//取前一个char的低2位和后一个的高4位
a=jiami[b+1]<<4;
jiemi[c+2]=zidian[(a>>2)+(jiami[b+2]>>6)];//取前一个char的低4位和后一个的高二位
a=jiami[b+2]<<2;
jiemi[c+3]=zidian[a>>2];//取最后一个的低6位
}
}
else if(n%3==1)
{
for(b=0,c=0;b<(n-(n%3));c+=4,b+=3)//这几处位运算分开是因为位运算特性:运算结束后补0
{
a=jiami[b]>>2;
jiemi[c]=zidian[a];
a=jiami[b]<<6;
jiemi[c+1]=zidian[(a>>2)+(jiami[b+1]>>4)];
a=jiami[b+1]<<4;
jiemi[c+2]=zidian[(a>>2)+(jiami[b+2]>>6)];
a=jiami[b+2]<<2;
jiemi[c+3]=zidian[a>>2];
}//因为余一,所以取最后的字符的高六位,作为一个字符,剩下的二位与四个0组成下个字符,剩下的两个密文字符全由0补齐
a=jiami[b]>>2;
jiemi[c]=zidian[a];
a=jiami[b]<<6;
jiemi[c+1]=zidian[a>>2];
jiemi[c+2]=zidian[0];
jiemi[c+3]=zidian[0];
}
else
{
for(b=0,c=0;b<(n-(n%3));c+=4,b+=3)//这几处位运算分开是因为位运算特性:运算结束后补0
{
a=jiami[b]>>2;
jiemi[c]=zidian[a];
a=jiami[b]<<6;
jiemi[c+1]=zidian[(a>>2)+(jiami[b+1]>>4)];
a=jiami[b+1]<<4;
jiemi[c+2]=zidian[(a>>2)+(jiami[b+2]>>6)];
a=jiami[b+2]<<2;
jiemi[c+3]=zidian[a>>2];
}//因为余二,所以取最后的字符的高六位,作为一个字符,剩下的二位与下个字符的高四位组成下个字符,剩下的两位与四位0补齐,最后的剩下的一个密文字符全由0补齐
a=jiami[b]>>2;
jiemi[c]=zidian[a];
a=jiami[b]<<6;
jiemi[c+1]=zidian[(a>>2)+(jiami[b+1]>>4)];
a=jiami[b+1]<<4;
jiemi[c+2]=zidian[a>>2];
jiemi[c+3]=zidian[0];
}
a=((n-n%3)/3)+1;
jiemi[4*a]='\0';
}
unsigned char found(char jiami)
{
unsigned char a;//char具有符号会出现复数等离奇情况 unsigned char无符号则无此情况
for(a=0;a<64;a++)
{
if(jiami==zidian[a])//与字典对应寻找密文对应的6位二进制数
return a;
}
}
void base64jiemi(char *jiami,int n,char *jiemi)//解密操作
{
int a,b;
unsigned char c;//char具有符号会出现复数等离奇情况 unsigned char无符号则无此情况
for(a=0,b=0;a<n;a+=4,b+=3)
{
jiemi[b]=(found(jiami[a])<<2)+(found(jiami[a+1])>>4);//8bit数需要6位和2位拼接此处都为拼接操作
c=found(jiami[a+1])<<4;
jiemi[b+1]=c+(found(jiami[a+2])>>2);
c=found(jiami[a+2])<<6;
jiemi[b+2]=c+found(jiami[a+3]);
}


}
int main()
{
int n,m,flag;
printf("请选择加密/解密 0/1");//加密解密二合一
scanf("%d",&flag);
getchar();
if(flag==0)
{
printf("请输入加密长度");
scanf("%d",&n);
getchar();//吸掉回车
char *jiami=(char*)calloc(n,sizeof(char));//申请连续的内存作为数组使用
fgets(jiami,n,stdin);
for(m=0;m<n;m++)
if(jiami[m]=='\n')
{
jiami[m]='\0';
break;
}
char *jiemi=(char*)calloc(4*(((n-n%3)/3)+1)-1,sizeof(char));
base64(jiami,m,jiemi);
puts(jiemi);
}
else if(flag==1)
{

printf("请输入解密长度");
scanf("%d",&n);
getchar();//吸掉回车
char *jiami=(char*)calloc(n,sizeof(char));//申请连续的内存作为数组使用
fgets(jiami,n,stdin);
for(m=0;m<n;m++)
if(jiami[m]=='\n')//fgets会吸掉回车,可以以回车来作为结束符
{
jiami[m]='\0';
break;
}
char *jiemi=(char*)calloc(m,sizeof(char));
base64jiemi(jiami,m,jiemi);
puts(jiemi);
}
return 0;
}

base58

进行大数运算将256进制转化为58进制,但longlongint有长度限制,此代码无法完全计算出超过7个字符的加密结果

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
145
#include<stdio.h>
#include<stdlib.h>
char zidian[] = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
static int e=98;
//下面为加密所用函数
long long int cifang(int a, int n)//计算a的n次方方便进行每次都取到两位来与字典一一对应
{
if (n == 1)
{
return (long long int)1;
}
return (long long int)a * cifang(a, n - 1);
}
long long int zhuanhua10(char* a, int n)//转化为十进制数
{
if (n == 1)
{
return (long long int) * a;
}
return (long long int)((*(a + n - 1)) + (zhuanhua10(a, n - 1) * 256));
}
long long int zhuanhua58(long long int n, int* p, int* flag)//转化为58进制数同时每两位表示一个58进制方便对字典进行比较
{
if (*flag == 0)//*p用来计算所存在的字符串长度方便从高位到低位输出,同时方便创造存放加密后密文的数组
{
*p = *p + 1;
}
if (n % 58 == 0)
{
if (*flag == 0)
{
*p = *p - 1;
}
return 0;
}
else
return n % 58 + zhuanhua58((long long int)(n - n % 58) / 58, p, flag) * 100;
}
void base58(char* jiami, int n, int* p, char* jiemi, int* flag)
{
int a, b;
long long int c;
c = zhuanhua58(zhuanhua10(jiami, n), p, flag);
for (a = *p, b = 0; a > 0; a--, b++)
{
jiemi[b] = zidian[(c / cifang(100, a)) - (c / cifang(100, a + 1)) * 100];

}
jiemi[b + 1] = '\0';

}
//下面为解密所用函数
long long int jiaoyan(char a)//与字典进行比较找到对应的58进制值
{
long long int b;
for(b=0;1;b++)
{
if(a==zidian[b])
{
return b;
}
}
}
long long int huifu10(char *jiami,long long int n)//将58进制值转化为10进制值
{
if(n==-1)
{

return 0;
}
return jiaoyan(jiami[n])+huifu10(jiami,n-1)*58;//从n开始是因为输入的数组第0位为高位,后位为低位,从最低位开始方便进行进制转化,且因为58进制数每位都要占两位所以乘了100
}
long long int huifu256(long long int n)
{
if(n==0)
{
return 0;
}
return n%256+huifu256((n-n%256)/256)*1000;//将10进制数转化为256进制(与ascii码对应)
}
void base58jiemi(char *jiemi,long long int n)
{
if(n%1000==0)
{
e++;//因为要输入所以前移一位但此时以经没有输入了就让数组指向最高位字符
return;
}
jiemi[e]=n%1000;//取低三位获取低位值
e--;//将数组前移一位
base58jiemi(jiemi,n/1000);
}
int main()
{
printf("请选择加密/解密:0/1");
int n;
scanf("%d",&n);
switch(n)
{
case 0:{
printf("请输入字符数");
scanf("%d", &n);
getchar();
char* jiami = (char*)calloc(n+2, sizeof(char));
fgets(jiami, n+2, stdin);
int jishu = 0;
int fla = 0;
int* flag = &fla;
int* pjishu = &jishu;
for (n = 0; 1; n++)
{
if (jiami[n] == '\n')
{
jiami[n] = '\0';
break;
}
}
zhuanhua58(zhuanhua10(jiami, n), pjishu, flag);
*flag = 1;
char* jiemi = (char*)calloc(*pjishu + 1, sizeof(char));
base58(jiami, n, pjishu, jiemi, flag);
puts(jiemi);
};break;
case 1:
{
printf("请输入字符数");
scanf("%d", &n);
getchar();
char* jiami = (char*)calloc(n+2, sizeof(char));
fgets(jiami, n+2, stdin);
for (n = 0; 1; n++)
{
if (jiami[n] == '\n')
{
jiami[n] = '\0';
break;
}
}
char jiemi[100]="\0";
jiemi[99]='\0';
base58jiemi(jiemi,huifu256(huifu10(jiami,n-1)));
puts(jiemi+e);
};break;
}
return 0;
}

RC4

通过特定规律(不同key不同规律)打乱数组,因所用的char为signedchar有128种,所以此处进行128字节加密

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
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int panduanweishu(int a)//判断key数位数,方便填充T表
{
int b,c;
for(b=1,c=10;1;b++,c*=10)
{
if(a/c==0)
return b;
}
}
void anweitianchongKbiao(int *T,int b,int weishu)//对T表进行填充
{
int a,c;
for(a=weishu-1,c=10;a>=0;a--,c*=10)
{
T[a]=b%c-b%(c/10);
}
for(a=weishu;a<128;a++)
{
T[a]=T[a%weishu];
}
}
void swap(int *a,int x,int y)
{
a[x]=a[x]^a[y];
a[y]=a[x]^a[y];
a[x]=a[x]^a[y];
}
int main()
{
int S[128],T[128],a,b,c,d,key;
char jiami[100],jiemi[100];
printf("请选择加密或解密 0/1:");
scanf("%d",&a);
getchar();
switch(a)
{
case 0:{
printf("请输入待加密字符");
gets(jiami);
printf("请输入初始KEY");
scanf("%d",&key);
getchar();
for(a=0;a<128;a++)
{
S[a]=a;//初始化S表
}
anweitianchongKbiao(T,key,panduanweishu(key));
for(a=0,b=0;a<128;a++)
{
b=(b+S[a]+T[a])%128;//通过T表提供顺序进行打乱S表
swap(S,a,b);//打乱操作
}
//取得密钥,同时加密
for(a=0,b=0,c=0;a<strlen(jiami);a++)//此处都为取得密码流操作对字符进行异或
{
b=(b+1)%128;
c=(c+S[b])%128;
swap(S,b,c);
d=(S[b]+S[c])%128;
key=S[d];
jiami[a]=jiami[a]^key;
}
puts(jiami);
}break;
case 1:{
printf("请输入待解密字符");//解密过程是通过相同的异或操作恢复原来的数据
gets(jiami);
printf("请输入初始KEY");
scanf("%d",&key);
getchar();
for(a=0;a<128;a++)
{
S[a]=a;
}
anweitianchongKbiao(T,key,panduanweishu(key));
for(a=0,b=0;a<128;a++)
{
b=(b+S[a]+T[a])%128;//通过T表提供顺序进行打乱S表
swap(S,a,b);//打乱操作
}
for(a=0,b=0,c=0;a<strlen(jiami);a++)
{
b=(b+1)%128;
c=(c+S[b])%128;
swap(S,b,c);
d=(S[b]+S[c])%128;
key=S[d];
jiami[a]=(unsigned char)jiami[a]^key;//通过异或相同的数来使其恢复
}

puts(jiami);
}break;
return 0;
}
}

Tea

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
#include <stdio.h>
#include <stdint.h>
void teajiami (uint32_t* v, uint32_t* k) //此处uint32长度就为usigned int占32bit共4个字节
{
uint32_t sum = 0; // 注意sum也是32位无符号整型
uint32_t v0 = v[0], v1 = v[1];
uint32_t delta = 0x9e3779b9;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];

for (int i=0; i<32; i++) //进行32轮迭代,次数越多越难破解,但同时效率也会降低
{
sum += delta;
v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);//此处可以作为检验tea加密的突破口,移位运算结合异或运算
v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
}

v[0]=v0;
v[1]=v1;
}

void teajiemi (uint32_t* v, uint32_t* k) //解密也是进行相同的异或操作,通过异或同一个数恢复原数
{
uint32_t v0 = v[0], v1 = v[1];
uint32_t delta = 0x9e3779b9;
uint32_t sum = delta * 32;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];

for (int i=0; i<32; i++) {
v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
sum -= delta;
}

v[0]=v0;
v[1]=v1;
}
int main()
{
// 两个32位无符号整数,即待加密的64bit明文数据
uint32_t v[2] = {0x12345678, 0x78563412};
// 四个32位无符号整数,即128bit的key
uint32_t k[4]= {0x1, 0x2, 0x3, 0x4};

printf("Data is : %x %x\n", v[0], v[1]);
teajiami(v, k);
printf("Encrypted data is : %x %x\n", v[0], v[1]);
teajiemi(v, k);
printf("Decrypted data is : %x %x\n", v[0], v[1]);

return 0;
}

XXTEA

待做,特征为加密轮数由加密个数决定

MD5

md5主要用于校验文件(不同的文件生成的md5码不同,通过检测传输前后的md5码可以检测其是否被篡改)

MD5可以将信息以512位来处理信息

主要是让信息长度比512的整数倍少64位(记录数据长度),若不足则进行填充(由一个一和对应的后续一段0表示)

再将对应的信息分块,每块有512位,再将每块再分为16个32位

用四组幻数进行循环计算(可用于检验是否位为MD5算法)

另外检验MD5算法一般可以看见较长的函数运算语句

  • 标题: 学习报告(三到四周)
  • 作者: runwu2204
  • 创建于 : 2023-01-05 17:05:20
  • 更新于 : 2023-01-05 17:05:20
  • 链接: https://runwu2204.github.io/2023/01/05/Re/实验室报告/学习报告(三到四周)/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论