常见的几种数据加密算法

常见的数据加密算法

一,数据加密的含义

数据加密(Data Encryption)指将一个信息(或称明文,plain text)经过加密钥匙(Encryption key)及加密函数转换,变成无意义的密文(cipher text),而接收方则将此密文经过解密函数、解密钥匙(Decryption key)还原成明文。加密技术是网络安全技术的基石。
数据加密,是一门历史悠久的技术,指通过加密算法和加密密钥将明文转变为密文,而解密则是通过解密算法和解密密钥将密文恢复为明文。它的核心是密码学。

数据加密仍是计算机系统对信息进行保护的一种最可靠的办法。它利用密码技术对信息进行加密,实现信息隐蔽,从而起到保护信息的安全的作用。

二,常见的加密算法的种类

1,对称加密

采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密。

亦指加密和解密使用相同密钥的加密算法。对称加密算法的优点在于加解密的高速度和使用长密钥时的难破解性。假设两个用户需要使用对称加密方法加密然后交换数据,则用户最少需要2个密钥并交换使用,如果企业内用户有n个,则整个企业共需要n×(n-1) 个密钥,密钥的生成和分发将成为企业信息部门的恶梦。对称加密算法的安全性取决于加密密钥的保存情况,但要求企业中每一个持有密钥的人都保守秘密是不可能的,他们通常会有意无意的把密钥泄漏出去——如果一个用户使用的密钥被入侵者所获得,入侵者便可以读取该用户密钥加密的所有文档,如果整个企业共用一个加密密钥,那整个企业文档的保密性便无从谈起。
常见的对称加密算法:DES,3DES,RC4,RC5,RC6,AES,IDEA

2.非对称加密

指加密和解密使用不同密钥的加密算法,也称为公私钥加密。假设两个用户要加密交换数据,双方交换公钥,使用时一方用对方的公钥加密,另一方即可用自己的私钥解密。如果企业中有n个用户,企业需要生成n对密钥,并分发n个公钥。由于公钥是可以公开的,用户只要保管好自己的私钥即可,因此加密密钥的分发将变得十分简单。同时,由于每个用户的私钥是唯一的,其他用户除了可以可以通过信息发送者的公钥来验证信息的来源是否真实,还可以确保发送者无法否认曾发送过该信息。非对称加密的缺点是加解密速度要远远慢于对称加密,在某些极端情况下,甚至能比非对称加密慢上1000倍。
常见的非对称加密算法:RSA、ECC(移动设备用)、Diffie-Hellman、El Gamal、DSA(数字签名用)

3.Hash算法

Hash算法特别的地方在于它是一种单向算法,用户可以通过Hash算法对目标信息生成一段特定长度的唯一的Hash值,却不能通过这个Hash值重新获得目标信息。因此Hash算法常用在不可还原的密码存储、信息完整性校验等。
常见的Hash算法:MD2、MD4、MD5、HAVAL、SHA、SHA-1、HMAC、HMAC-MD5、HMAC-SHA1

三,几种常用的加密算法

1 DES

### 1.1  DES算法的原理

DES算法使用一个56位的密钥以及附加的8位奇偶校验位,产生最大64位的分组大小。是一个迭代的分组密码,其中将加密的文本块分成两半。使用子密钥对其中一半应用循环功能,然后将输出与另一半进行“异或”运算;接着交换这两半,这一过程会继续下去,但最后一个循环不交换。DES使用16轮循环,使用异或,置换,代换,移位操作四种基本运算。

1.2 DES算法的特点

DES算法产生密钥的方式简单,密钥一般也比较短。
DES算法加密解密速度快,效率很高,适合对大数据量的数据进行加密。
DES算法的安全性依赖于密钥的高度保密,通信双方必须有方法能保证安全的分享密钥,并定期更换DES密钥。

1.3 DES算法的源代码

#include<stdio.h>  
#include<string.h>  
//#define gets_s gets   //出现[Error] 'gets_s' was not declared in this scope的话就加上这句,默认使用的gcc编译器的话会出现此错误,因为gets_s是vs提供的函数
int IP_Table[64] = {                                     //IP置换矩阵  
	58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
	62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
	57, 49, 41, 33, 25, 17,  9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
	61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7 };
int E_Table[48] = {                                    //扩展矩阵  
	32,  1,  2,  3,  4,  5,  4,  5,  6,  7,  8,  9,
	8,  9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17,
	16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25,
	24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32,  1 };
int P_Table[32] = {                                             //  P 盒  
	16, 7, 20, 21, 29, 12, 28, 17, 1,  15, 23, 26, 5,  18, 31, 10,
	2,  8, 24, 14, 32, 27, 3,  9,  19, 13, 30, 6,  22, 11, 4,  25 };
int IPR_Table[64] = {                                    //逆IP置换矩阵  
	40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31,
	38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29,
	36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27,
	34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41,  9, 49, 17, 57, 25 };
int PC1_Table[56] = {                               //密钥第一次置换矩阵  
	57, 49, 41, 33, 25, 17,  9,  1, 58, 50, 42, 34, 26, 18,
	10,  2, 59, 51, 43, 35, 27, 19, 11,  3, 60, 52, 44, 36,
	63, 55, 47, 39, 31, 23, 15,  7, 62, 54, 46, 38, 30, 22,
	14,  6, 61, 53, 45, 37, 29, 21, 13,  5, 28, 20, 12,  4 };
int PC2_Table[48] = {                          // 密钥第二次置换矩阵  
	14, 17, 11, 24,  1,  5,  3, 28, 15,  6, 21, 10,
	23, 19, 12,  4, 26,  8, 16,  7, 27, 20, 13,  2,
	41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
	44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32 };
int S_Box[8][4][16] = {                     //8个S盒   三维数组  
											// S1   
	14, 4,  13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7,
	0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8,
	4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0,
	15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13,
	// S2   
	15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10,
	3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5,
	0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15,
	13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9,
	// S3   
	10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8,
	13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1,
	13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7,
	1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12,
	// S4   
	7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15,
	13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9,
	10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4,
	3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14,
	// S5   
	2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9,
	14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6,
	4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14,
	11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3,
	// S6   
	12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11,
	10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8,
	9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6,
	4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13,
	// S7   
	4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1,
	13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6,
	1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2,
	6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12,
	// S8   
	13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7,
	1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2,
	7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8,
	2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11
};
static void CharToBit(const char input[], int output[], int bits)//把CHAR转换为INT  
{
	int i, j;
	for (j = 0; j<8; j++)
	{
		for (i = 0; i<8; i++)
		{
			output[7 * (j + 1) - i + j] = (input[j] >> i) & 1;
		}
	}
};
static void BitToChar(const int intput[], char output[], int bits)//把INT转换为CHAR  
{
	int i, j;
	for (j = 0; j<8; j++)
	{
		for (i = 0; i<8; i++)
		{
			output[j] = output[j] * 2 + intput[i + 8 * j];
		}
	}
};
static void Xor(int *INA, int *INB, int len)//异或操作  
{
	int i;
	for (i = 0; i<len; i++)
	{
		*(INA + i) = *(INA + i) ^ *(INB + i);
	}
};
static  void IP(const int input[64], int output[64], int table[64])//初始IP置换  
{
	int i;
	for (i = 0; i<64; i++)
	{
		output[i] = input[table[i] - 1];//减1操作不可少!!  
	}
};
static  void E(const int input[32], int output[48], int table[48])//E扩展  
{
	int i;
	for (i = 0; i<48; i++)
	{
		output[i] = input[table[i] - 1];
	}
};
static  void P(const int input[32], int output[32], int table[32])//P置换  
{
	int i;
	for (i = 0; i<32; i++)
	{
		output[i] = input[table[i] - 1];
	}
};
static  void IP_In(const int input[64], int output[64], int table[64])//逆IP  
{
	int i;
	for (i = 0; i<64; i++)
	{
		output[i] = input[table[i] - 1];
	}
};
static  void PC_1(const int input[64], int output[56], int table[56])//PC_1  
{
	int i;
	for (i = 0; i<56; i++)
	{
		output[i] = input[table[i] - 1];
	}
};
static  void PC_2(const int input[56], int output[48], int table[48])//PC_2  
{
	int i;
	for (i = 0; i<48; i++)
	{
		output[i] = input[table[i] - 1];
	}
};
static  void S(const int input[48], int output[32], int table[8][4][16])//S盒压缩  
{
	int i = 0;
	int j = 0;
	int INT[8];
	for (; i<48; i = i + 6)
	{
		INT[j] = table[j][(input[i] << 1) + (input[i + 5])][(input[i + 1] << 3) + (input[i + 2] << 2) + (input[i + 3] << 1) + (input[i + 4])];
		j++;
	}
	for (j = 0; j<8; j++)
	{
		for (i = 0; i<4; i++)
		{
			output[3 * (j + 1) - i + j] = (INT[j] >> i) & 1;
		}
	}
};
static void F_func(int input[32], int output[32], int subkey[48])//完成DES算法轮变换  
{
	int len = 48;
	int temp[48] = { 0 };
	int temp_1[32] = { 0 };
	E(input, temp, E_Table);
	Xor(temp, subkey, len);
	S(temp, temp_1, S_Box);
	P(temp_1, output, P_Table);
};
static void RotateL(const int input[28], int output[28], int leftCount)//秘钥循环左移  
{
	int i;
	int len = 28;
	for (i = 0; i<len; i++)
	{
		output[i] = input[(i + leftCount) % len];
	}
};
static void  subKey_fun(const int input[64], int Subkey[16][48])//子密钥生成  
{
	int loop = 1, loop_2 = 2;
	int i, j;
	int c[28], d[28];
	int pc_1[56] = { 0 };
	int pc_2[16][56] = { 0 };
	int rotatel_c[16][28] = { 0 };
	int rotatel_d[16][28] = { 0 };
	PC_1(input, pc_1, PC1_Table);
	for (i = 0; i<28; i++)
	{
		c[i] = pc_1[i];
		d[i] = pc_1[i + 28];
	}
	int leftCount = 0;
	for (i = 1; i<17; i++)
	{
		if (i == 1 || i == 2 || i == 9 || i == 16)
		{
			leftCount += loop;
			RotateL(c, rotatel_c[i - 1], leftCount);
			RotateL(d, rotatel_d[i - 1], leftCount);
		}
		else
		{
			leftCount += loop_2;
			RotateL(c, rotatel_c[i - 1], leftCount);
			RotateL(d, rotatel_d[i - 1], leftCount);
		}
	}
	for (i = 0; i<16; i++)
	{
		for (j = 0; j<28; j++)
		{
			pc_2[i][j] = rotatel_c[i][j];
			pc_2[i][j + 28] = rotatel_d[i][j];
		}
	}
	for (i = 0; i<16; i++)
	{
		PC_2(pc_2[i], Subkey[i], PC2_Table);
	}
};
static void  DES_Efun(char input[8], char key_in[8], int output[64])
{
	int Ip[64] = { 0 };//存储初始置换后的矩阵  
	int output_1[64] = { 0 };
	int subkeys[16][48];
	int chartobit[64] = { 0 };
	int key[64];
	int l[17][32], r[17][32];
	CharToBit(input, chartobit, 8);//正确,转换为64个二进制数的操作正确!  
	IP(chartobit, Ip, IP_Table);//正确,IP初始置换!  
	CharToBit(key_in, key, 8);//正确!  
	subKey_fun(key, subkeys);//正确!  
	for (int i = 0; i<32; i++)
	{
		l[0][i] = Ip[i];
		r[0][i] = Ip[32 + i];
	}
	for (int j = 1; j<16; j++)//前15轮的操作  
	{
		for (int k = 0; k<32; k++)
		{
			l[j][k] = r[j - 1][k];
		}
		F_func(r[j - 1], r[j], subkeys[j - 1]);
		Xor(r[j], l[j - 1], 32);
	}
	int t = 0;
	for (t = 0; t<32; t++)//最后一轮的操作  
	{
		r[16][t] = r[15][t];
	}
	F_func(r[15], l[16], subkeys[15]);
	Xor(l[16], l[15], 32);
	for (t = 0; t<32; t++)
	{
		output_1[t] = l[16][t];
		output_1[32 + t] = r[16][t];
	}
	IP_In(output_1, output, IPR_Table);
};
static void  DES_Dfun(int input[64], char key_in[8], char output[8])
{
	int Ip[64] = { 0 };//存储初始置换后的矩阵  
	int output_1[64] = { 0 };
	int output_2[64] = { 0 };
	int subkeys[16][48];
	int chartobit[64] = { 0 };
	int key[64];
	int l[17][32], r[17][32];
	IP(input, Ip, IP_Table);//正确,IP初始置换!  
	CharToBit(key_in, key, 8);//正确!  
	subKey_fun(key, subkeys);//正确!  
	for (int i = 0; i<32; i++)
	{
		l[0][i] = Ip[i];
		r[0][i] = Ip[32 + i];
	}
	for (int j = 1; j<16; j++)//前15轮的操作  
	{
		for (int k = 0; k<32; k++)
		{
			l[j][k] = r[j - 1][k];
		}
		F_func(r[j - 1], r[j], subkeys[16 - j]);
		Xor(r[j], l[j - 1], 32);
	}
	int t = 0;
	for (t = 0; t<32; t++)//最后一轮的操作  
	{
		r[16][t] = r[15][t];
	}
	F_func(r[15], l[16], subkeys[0]);
	Xor(l[16], l[15], 32);
	for (t = 0; t<32; t++)
	{
		output_1[t] = l[16][t];
		output_1[32 + t] = r[16][t];
	}
	IP_In(output_1, output_2, IPR_Table);
	BitToChar(output_2, output, 8);
};
int main()
{
	int output[64] = { 0 };
	char MIN[9] = { 0 };
	char MI[9] = { 0 };
	printf("请输入明文(8字节)\n");
	gets_s(MIN);
	printf("请输入秘钥(8字节)\n");
	gets_s(MI);
	DES_Efun(MIN, MI, output);
	printf("密文如下:\n");
	for (int i = 0; i<64; i++)
	{
		printf("%d", output[i]);
		if ((i + 1) % 4 == 0)
			printf("\n");
	}
	printf("\n");
 
        for(int i=0;i<8;i++) MIN[i]='0';//评论区见到有人不服,没看懂函数就说删掉解密部分输出明文没变,那就在解密前加上个赋值,你再试试?
 
	printf("解密功能\n");
	DES_Dfun(output, MI, MIN);
	printf("明文如下:\n");
	for (int i = 0; i<8; i++)
	{
		printf("%c", MIN[i]);
	}
	printf("\n\n");
	return 0;
}


2 RSA算法

2.1 RSA算法的含义

RSA算法是现今使用最广泛的公钥密码算法,也是号称地球上最安全的加密算法。在了解RSA算法之前,先熟悉下几个术语 

根据密钥的使用方法,可以将密码分为对称密码和公钥密码
对称密码:加密和解密使用同一种密钥的方式
公钥密码:加密和解密使用不同的密码的方式,因此公钥密码通常也称为非对称密码。

2.2 RSA算法加密解密过程

RSA的加密过程可以使用一个通式来表达

密文=明文EmodN密文=明文EmodN
也就是说RSA加密是对明文的E次方后除以N后求余数的过程。就这么简单?对,就是这么简单。
从通式可知,只要知道E和N任何人都可以进行RSA加密了,所以说E、N是RSA加密的密钥,也就是说E和N的组合就是公钥,我们用(E,N)来表示公钥

公钥=(E,N)公钥=(E,N)
不过E和N不并不是随便什么数都可以的,它们都是经过严格的数学计算得出的,关于E和N拥有什么样的要求及其特性后面会讲到。顺便啰嗦一句E是加密(Encryption)的首字母,N是数字(Number)的首字母

  1. RSA解密
    RSA的解密同样可以使用一个通式来表达

明文=密文DmodN明文=密文DmodN

也就是说对密文进行D次方后除以N的余数就是明文,这就是RSA解密过程。知道D和N就能进行解密密文了,所以D和N的组合就是私钥

私钥=(D,N)私钥=(D,N)

从上述可以看出RSA的加密方式和解密方式是相同的,加密是求“E次方的mod N”;解密是求“D次方的mod N”
此处D是解密(Decryption)的首字母;N是数字(Number)的首字母。
在这里插入图片描述

2.3 RSA算法源代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
int prime[1305];//存放素数

int p[10005];//用筛选法求素数 
void PRIME(){
	int i,i2,k;
    for(i=0;i<=10000;i+=2)
   		p[i]=0; 
    for(i=1;i<=10000;i+=2)
   		p[i]=1; 
    p[2]=1;p[1]=0;
    for(i=3;i<=100;i+=2){ 
    	if(p[i]==1){
     		i2=i+i; 
     		k=i2+i;
            while(k<=10000){
      		p[k]=0;
      		k+=i2;
     		}	
    	}
	}
	prime[0]=1;
	prime[1]=2;
	for(i=3;i<=10000;i+=2)
   		if(p[i])
    		prime[++prime[0]]=i;

}
// 计算逆元素
__int64 mod(__int64 a,__int64 n){
	return (a%n+n)%n;
}
void gcd(__int64 a,__int64 b,__int64 &d,__int64 &x,__int64 &y){
	if(b==0)
	{	
   		d=a;
   		x=1;
   		y=0;
   		return;
	}
    gcd(b,a%b,d,y,x);
    y-=x*(a/b);
}
//a-1 mod n
__int64 Inv(__int64 a,__int64 n){ // 计算逆元素
	__int64 d,x,y;
	gcd(a,n,d,x,y);
    if(d==1)
   		return mod(x,n);
	else 
   		return -1;
}
//求两个数的最大公约数
__int64 GCD(__int64 n,__int64 m){
	__int64 t,r;
	if(n<m){
   		t=n;
   		n=m;
   		m=t;
	}
	while((r=n%m)!=0){
   		n=m;
   		m=r;
	}
	return m;
}
//x=a^b(mod n)
__int64 ModPow(__int64 a,__int64 b,__int64 n){
	__int64 d=1,i=0;
	while(b>=(1<<i)) i++;
	for(--i;i>=0;--i){
   		d=d*d%n;
   		if(b&(1<<i))
    		d=d*a%n;
	}
	return d;
}
int main(){
	__int64 i,e,d,n,st,ed,eula;
	__int64 m,c,ans;
	PRIME();
	printf("素数的个数:%d\n",prime[0]);
	printf("选择两个不同的素数(输入编号,空格隔开):\n");//47和71分别是第15个和20个 
	while(scanf("%I64d%I64d",&st,&ed)!=EOF){
		printf("你选择的两个素数分别是:%d和%d\n",prime[st],prime[ed]);
   		n=prime[st]*prime[ed];
   		printf("计算得到N是%I64d\n",n);
   		//N的Eula数
   		eula=(prime[st]-1)*(prime[ed]-1);
   		//找一个与eula互质的数
   		for(i=2;i<eula;i++)
    		if(GCD(eula,i)==1){
     			e=i;
     			break;
    		}
    	//e=79; 
   		//上面找到了公开密钥n--e
   		d=Inv(e,eula);
		//上面找到了私密钥n--d
   		printf("生成公钥:(%I64d %I64d)\n",e,n);
   		//输出密钥
  		printf("生成私钥:(%I64d %I64d)\n",d,n);
   		//切忌加密的数要比n小
   		printf("请输入要加密的数(<N)\n");
   		scanf("%I64d",&m);
   		c=ModPow(m,e,n);
   		printf("通过计算%I64d^%I64d(mod %I64d)得到密文=%I64d\n",m,e,n,c);
   		ans=ModPow(c,d,n);
  		printf("通过计算%I64d^%I64d(mod %I64d)得到明文=%I64d\n",c,d,n,ans);
  		printf("素数的个数:%d\n",prime[0]);
		printf("选择两个不同的素数(输入编号,空格隔开):\n");//47和71分别是第15个和20个 
	}
	return 0;
}

  • 1
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值