数据摘要加密解密(五)

加密功能都实现了,现在来实现解密,解密和加密大体相同。解密接口继承安全接口,抽象类进行实现

解密主要是实现DES、3DES、AES、RSA,直接见程序

IDecrypt接口,和加密接口一样空接口

1 package com.xqrj.security.decrypt;
2
3 import com.xqrj.security.ISecurity;
4
5 public interface IDecrypt extends ISecurity {
6
7 }

DesDecryptImpl解密抽象类,主要功能要此类中实现

 1 package com.xqrj.security.decrypt;
2
3 import javax.crypto.Cipher;
4 import javax.crypto.SecretKey;
5 import javax.crypto.spec.SecretKeySpec;
6
7 import com.xqrj.util.PublicUtil;
8
9 public abstract class DesDecryptImpl implements IDecrypt {
10 protected String algorithm = "DES";
11 protected int encodeMode = 1;
12 protected byte[] key;
13 protected byte[] otherData = "DES/ECB/NoPadding".getBytes();
14
15 public byte[] buildData(byte[] buff) {
16 try {
17 switch(encodeMode) {
18 case 1: //BASE64
19 buff = PublicUtil.getBase64Decode(new String(buff));
20 break;
21 case 2: //HEX
22 buff = PublicUtil.hexToBytes(buff);
23 break;
24 default: //BASE64
25 buff = PublicUtil.getBase64Decode(new String(buff));
26 }
27 SecretKey secureKey = new SecretKeySpec(key,algorithm);
28 //Cipher对象实际完成加密操作
29 Cipher cipher = Cipher.getInstance(new String(otherData));
30 //用密匙初始化Cipher对象
31 cipher.init(Cipher.DECRYPT_MODE, secureKey);
32 //执行加密操作
33 return cipher.doFinal(buff);
34 } catch(Exception e) {
35 e.printStackTrace();
36 throw new SecurityException("DesDecrypt对数据解密时出错!");
37 }
38 }
39
40 public void setAlgorithm(String algorithm) {
41 this.algorithm = algorithm;
42 }
43 public void setEncodeMode(int encodeMode) {
44 this.encodeMode = encodeMode;
45 }
46 public void setKey(byte[] key) {
47 this.key = key;
48 }
49 public void setOther(byte[] otherData) {
50 this.otherData = otherData;
51 }
52 /**
53 * 获取数据填充后的数据
54 * VC不足八的倍数后面添0,JAVA为不填充,所以补足8的倍数后面添0
55 * @param data 需要填充的数据
56 * @return void
57 */
58 private byte[] getNoPaddingBytes(byte[] data) {
59 int len = data.length;
60 int temp = len%8;
61 if (temp > 0) {
62 //取得总长度
63 len = len + (8-temp);
64 }
65 byte[] res = new byte[len];
66
67 System.arraycopy(data, 0, res, 0, data.length);
68 return res;
69 }
70 }

DesDecrypt类,继承DesDecryptImpl主要用于供其它类调用

1 package com.xqrj.security.decrypt;
2
3 public class DesDecrypt extends DesDecryptImpl {
4
5 }

DES、3DES、AES都用以上类进行实现,只是在调用时传入不同的参数即可,最后会将测试程序附上。

RSA解密也分发公钥解密和私钥解密,在定义RSA加密时写义了IRsaEncrypt接口,发现解密时也在定义这样一个接口就重复了,所以决定将此接口改为IRsaSecurity供加密和解密同时实现

这样此接口只能用于RSA加密解密

IRsaSecurity类

 1 package com.xqrj.security;
2
3 import java.security.PrivateKey;
4 import java.security.PublicKey;
5 import java.security.cert.Certificate;
6
7 public interface IRsaSecurity extends ISecurity {
8 /**
9 * 设置证书
10 * @param certificate 设置证书对象
11 * @return void
12 */
13 public void setCertificate(Certificate certificate);
14 /**
15 * 设置公钥
16 * @param publicKey 设置公钥对象
17 * @return void
18 */
19 public void setPublicKey(PublicKey publicKey);
20 /**
21 * 设置私钥
22 * @param privateKey 设置私钥对象
23 * @return void
24 */
25 public void setPrivateKey(PrivateKey privateKey);
26 }

RsaDecryptImpl解密抽象类,此类主要还是构造方法用于加载证书里的公钥及私钥

  1 package com.xqrj.security.decrypt;
2
3 import java.io.FileInputStream;
4 import java.io.FileOutputStream;
5 import java.io.IOException;
6 import java.security.KeyStore;
7 import java.security.PrivateKey;
8 import java.security.PublicKey;
9 import java.security.cert.Certificate;
10 import java.util.Enumeration;
11
12 import javax.crypto.Cipher;
13 import javax.crypto.SecretKey;
14 import javax.crypto.spec.SecretKeySpec;
15
16 import com.xqrj.security.IRsaSecurity;
17 import com.xqrj.util.PublicUtil;
18
19 public abstract class RsaDecryptImpl implements IRsaSecurity {
20 protected String algorithm = "RSA";
21 protected int encodeMode = 0;
22 protected byte[] key;
23 /*
24 * 使用RSA算法(RSA,RSA/ECB/PKCS1Padding为117位,NoPadding为128位)
25 * RSA/ECB/PKCS1Padding的方式是按照PKCS1的标准.即输入数据长度小于等于密钥的位数/8-11
26 * 例如:1024位密钥,1024/8-11=117.不足的部分,程序会自动补齐.加密后的数据还是等于密钥的位数/8-11(8至11之间)
27 * 如果不指定,那么输入数据就必须等于密钥的位数/8
28 */
29 protected byte[] otherData = "RSA/ECB/PKCS1Padding".getBytes();
30
31 /** 服务器证书 */
32 protected Certificate certificate = null;
33 /** 服务器公钥 */
34 protected PublicKey publicKey = null;
35 /** 服务器私钥 */
36 protected PrivateKey privateKey = null;
37
38 public RsaDecryptImpl() {
39
40 }
41
42 public RsaDecryptImpl(String certFile,String certPass) {
43 FileInputStream fis = null;
44 FileOutputStream ois = null;
45 String KeyType = "PKCS12";
46 try {
47 KeyStore keyStore = KeyStore.getInstance(KeyType);
48 fis = new FileInputStream(certFile);
49 char[] password = null;
50 if ((null!=certPass) && !"".equals(certPass)) {
51 password = certPass.toCharArray();
52 }
53 keyStore.load(fis, password);
54 fis.close();
55 Enumeration enums = keyStore.aliases();
56 String keyAlias = null;
57 if (enums.hasMoreElements()) {
58 keyAlias = (String)enums.nextElement();
59 }
60
61 privateKey = (PrivateKey)keyStore.getKey(keyAlias, password);
62 certificate = keyStore.getCertificate(keyAlias);
63 publicKey = certificate.getPublicKey();
64 } catch (Exception e) {
65 e.printStackTrace();
66 } finally {
67 if (null!=ois) try {ois.close();} catch (IOException e) {e.printStackTrace();}
68 if (null!=fis) try {fis.close();} catch (IOException e) {e.printStackTrace();}
69 }
70 }
71
72 public byte[] buildData(byte[] buff) throws SecurityException {
73 try {
74 //获取证书取得私钥进行加密
75 if (null==privateKey) {
76 throw new SecurityException("私钥对象为空,无法进行数据加密!");
77 }
78 //判断加密的数据长度不可以大于128
79 if (buff.length>128) {
80 throw new SecurityException("加密数据长度超过128位,无法进行数据加密!");
81 }
82 //判断加密的数据长度不可以大于128
83 if (buff.length>128) {
84 throw new SecurityException("加密数据长度超过128位,无法进行数据加密!");
85 }
86 switch(encodeMode) {
87 case 1: //BASE64
88 buff = PublicUtil.getBase64Decode(new String(buff));
89 break;
90 case 2: //HEX
91 buff = PublicUtil.hexToBytes(buff);
92 break;
93 default: //BASE64
94 buff = PublicUtil.getBase64Decode(new String(buff));
95 }
96 //Cipher对象实际完成加密操作
97 Cipher cipher = Cipher.getInstance(new String(otherData));
98 //用密匙初始化Cipher对象
99 cipher.init(Cipher.DECRYPT_MODE, privateKey);
100 //执行加密操作
101 return cipher.doFinal(buff);
102 } catch(SecurityException e) {
103 throw new SecurityException(e.getMessage());
104 } catch(Exception e) {
105 e.printStackTrace();
106 throw new SecurityException("RsaEncrypt对数据解密时出错!");
107 }
108 }
109
110 public void setCertificate(Certificate certificate) {
111 this.certificate = certificate;
112 }
113
114 public void setPrivateKey(PrivateKey privateKey) {
115 this.privateKey = privateKey;
116 }
117
118 public void setPublicKey(PublicKey publicKey) {
119 this.publicKey = publicKey;
120 }
121
122 public void setAlgorithm(String algorithm) {
123 this.algorithm = algorithm;
124 }
125
126 public void setEncodeMode(int encodeMode) {
127 this.encodeMode = encodeMode;
128 }
129
130 public void setKey(byte[] key) {
131 this.key = key;
132 }
133
134 public void setOther(byte[] otherData) {
135 this.otherData = otherData;
136 }
137 }

RsaPublicDecrypt公钥解密类,同时在此类中增加了验签方法,本想将签名、验签在接口中声明,但是后来觉得如果声明了各实现类里都得有此方法,意思上会造成误解,所以直接在类里实现都是私钥签名、公钥验签

 1 package com.xqrj.security.decrypt;
2
3 import java.security.PrivateKey;
4 import java.security.PublicKey;
5 import java.security.Signature;
6 import java.security.cert.Certificate;
7
8 import javax.crypto.Cipher;
9
10 import com.xqrj.security.encrypt.RsaEncryptImpl;
11 import com.xqrj.util.PublicUtil;
12
13 public class RsaPublicDecrypt extends RsaDecryptImpl {
14 public RsaPublicDecrypt(String certFile, String certPass) {
15 super(certFile, certPass);
16 }
17 public byte[] buildData(byte[] buff) throws SecurityException {
18 try {
19 //获取证书取得公钥进行加密
20 if (null==publicKey) {
21 //证书为空判断公钥是否为空
22 if (null==certificate) {
23 throw new SecurityException("获取公钥失败,无法进行数据解密!");
24 } else {
25 this.publicKey = (PublicKey)certificate.getPublicKey();
26 }
27 }
28 switch(encodeMode) {
29 case 1: //BASE64
30 buff = PublicUtil.getBase64Decode(new String(buff));
31 break;
32 case 2: //HEX
33 buff = PublicUtil.hexToBytes(buff);
34 break;
35 default: //BASE64
36 buff = PublicUtil.getBase64Decode(new String(buff));
37 }
38 //Cipher对象实际完成加密操作
39 Cipher cipher = Cipher.getInstance(new String(otherData));
40 //用密匙初始化Cipher对象
41 cipher.init(Cipher.DECRYPT_MODE, publicKey);
42 //执行加密操作
43 return cipher.doFinal(buff);
44 } catch(SecurityException e) {
45 throw new SecurityException(e.getMessage());
46 } catch(Exception e) {
47 e.printStackTrace();
48 throw new SecurityException("RsaPublicDecrypt对数据解密时出错!");
49 }
50 }
51 /**
52 * 校验签名数据
53 * @param buff 原始数据
54 * @param sign 签名后的数据
55 * @return boolean true:验证成功 false:验证失败
56 */
57 public boolean verifySignData(byte[] buff,byte[] sign) throws SecurityException {
58 try {
59 //获取证书取得公钥进行加密
60 if (null==publicKey) {
61 //证书为空判断公钥是否为空
62 if (null==certificate) {
63 throw new SecurityException("获取公钥失败,无法验证签名数据!");
64 } else {
65 this.publicKey = (PublicKey)certificate.getPublicKey();
66 }
67 }
68 switch(encodeMode) {
69 case 1: //BASE64
70 sign = PublicUtil.getBase64Decode(new String(sign));
71 break;
72 case 2: //HEX
73 sign = PublicUtil.hexToBytes(sign);
74 break;
75 default: //BASE64
76 sign = PublicUtil.getBase64Decode(new String(sign));
77 }
78
79 //对数据进行签名
80 Signature signature = Signature.getInstance(this.algorithm);
81 signature.initVerify(publicKey);
82 signature.update(buff);
83
84 return signature.verify(sign);
85 } catch(SecurityException e) {
86 throw new SecurityException(e.getMessage());
87 } catch(Exception e) {
88 e.printStackTrace();
89 throw new SecurityException("RsaPublicDecrypt验证签名数据时出错!");
90 }
91 }
92 }

RsaPrivateDecrypt私钥解密类

 1 package com.xqrj.security.decrypt;
2
3 import java.security.PrivateKey;
4 import java.security.PublicKey;
5 import java.security.Signature;
6 import java.security.cert.Certificate;
7
8 import javax.crypto.Cipher;
9
10 import com.xqrj.security.encrypt.RsaEncryptImpl;
11 import com.xqrj.util.PublicUtil;
12
13 public class RsaPrivateDecrypt extends RsaDecryptImpl {
14 public RsaPrivateDecrypt(String certFile, String certPass) {
15 super(certFile, certPass);
16 }
17 public byte[] buildData(byte[] buff) throws SecurityException {
18 try {
19 //获取证书取得私钥进行加密
20 if (null==privateKey) {
21 throw new SecurityException("私钥对象为空,无法进行数据解密!");
22 }
23 switch(encodeMode) {
24 case 1: //BASE64
25 buff = PublicUtil.getBase64Decode(new String(buff));
26 break;
27 case 2: //HEX
28 buff = PublicUtil.hexToBytes(buff);
29 break;
30 default: //BASE64
31 buff = PublicUtil.getBase64Decode(new String(buff));
32 }
33 //Cipher对象实际完成加密操作
34 Cipher cipher = Cipher.getInstance(new String(otherData));
35 //用密匙初始化Cipher对象
36 cipher.init(Cipher.DECRYPT_MODE, privateKey);
37 //执行加密操作
38 return cipher.doFinal(buff);
39 } catch(SecurityException e) {
40 throw new SecurityException(e.getMessage());
41 } catch(Exception e) {
42 e.printStackTrace();
43 throw new SecurityException("RsaPrivateDecrypt对数据解密时出错!");
44 }
45 }
46 }

PublicUtil类,加密解密中都用到了这个工具类,一直忘上传了

 1 /**
2 *
3 */
4 package com.xqrj.util;
5
6 import java.io.IOException;
7
8 import sun.misc.BASE64Decoder;
9 import sun.misc.BASE64Encoder;
10
11 public class PublicUtil {
12 private static final char[] DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
13 /**
14 * byte[] 转换为char[]
15 * @param data 数组数据
16 * @return char[] 字符数据
17 */
18 public static char[] bytesToHex(byte[] data) {
19 int l = data.length;
20 char[] res = new char[l << 1];
21 for (int i = 0, j = 0; i < l; i++) {
22 res[j++] = DIGITS[(0xF0 & data[i]) >>> 4];
23 res[j++] = DIGITS[0x0F & data[i]];
24 }
25 return res;
26 }
27 /**
28 * byte[] 转换为byte[]
29 * @param data 数组数据
30 * @return byte[] 字符数据
31 */
32 public static byte[] hexToBytes(byte[] data) {
33 if (null==data) return null;
34
35 String hexData = new String(data);
36 hexData = hexData.toUpperCase();
37 int len = hexData.length()/2;
38 char[] hexChars = hexData.toCharArray();
39 byte[] buff = new byte[len];
40 for(int i=0;i<len;i++) {
41 int pos = i*2;
42 buff[i] = (byte)(charToByte(hexChars[pos])<<4|charToByte(hexChars[pos+1]));
43
44 }
45 return buff;
46 }
47 private static byte charToByte(char c) {
48 return (byte)"0123456789ABCDEF".indexOf(c);
49 }
50 /**
51 * 获取BASE64编码数据
52 * @param data 数据
53 * @return String BASE64编码后的数据
54 */
55 public static String getBase64Encode(byte[] data) {
56 BASE64Encoder encoder = new sun.misc.BASE64Encoder();
57 return encoder.encode(data);
58 }
59 /**
60 * 获取BASE64解码数据
61 * @param data 数据
62 * @return byte[] BASE64解码后的数据
63 */
64 public static byte[] getBase64Decode(String data) throws IOException {
65 BASE64Decoder decoder = new sun.misc.BASE64Decoder();
66 return decoder.decodeBuffer(data);
67 }
68 }

SecurityTest测试类

  1 package com.xqrj.security;
2
3 import java.security.Security;
4
5 import com.xqrj.security.decrypt.DesDecrypt;
6 import com.xqrj.security.decrypt.RsaPrivateDecrypt;
7 import com.xqrj.security.decrypt.RsaPublicDecrypt;
8 import com.xqrj.security.digest.DigestDigest;
9 import com.xqrj.security.encrypt.DesEncrypt;
10 import com.xqrj.security.encrypt.RsaPrivateEncrypt;
11 import com.xqrj.security.encrypt.RsaPublicEncrypt;
12
13 public class SecurityTest {
14 public static void main(String[] args) {
15 //需要加密的数据
16 byte[] buff = "abcdefgh12345678".getBytes();
17 //密钥KEY
18 String key = "";
19 //使用何种算法
20 String algorithm = "";
21 //其它数据
22 String other = "";
23 //数据编码(1:BASE64 2:HEX)
24 int encodeMode = 1;
25 //结果数据
26 byte[] resBuff = null;
27 try {
28 //*********************************************************************************
29 //摘要测试
30 DigestDigest digestEncrypt = new DigestDigest();
31 //MD2、MD5用HEX进行编码
32 digestEncrypt.setAlgorithm("MD2");
33 digestEncrypt.setEncodeMode(2);
34 resBuff = digestEncrypt.buildData(buff);
35 System.out.println("生成的MD2摘要数据:"+new String(resBuff));
36 digestEncrypt.setAlgorithm("MD5");
37 resBuff = digestEncrypt.buildData(buff);
38 System.out.println("生成的MD5摘要数据:"+new String(resBuff));
39 //SHA用BASE进行编码
40 digestEncrypt.setAlgorithm("SHA");
41 digestEncrypt.setEncodeMode(1);
42 resBuff = digestEncrypt.buildData(buff);
43 System.out.println("生成的SHA-1摘要数据:"+new String(resBuff));
44 digestEncrypt.setAlgorithm("SHA-256");
45 resBuff = digestEncrypt.buildData(buff);
46 System.out.println("生成的SHA-256摘要数据:"+new String(resBuff));
47 digestEncrypt.setAlgorithm("SHA-384");
48 resBuff = digestEncrypt.buildData(buff);
49 System.out.println("生成的SHA-384摘要数据:"+new String(resBuff));
50 digestEncrypt.setAlgorithm("SHA-512");
51 resBuff = digestEncrypt.buildData(buff);
52 System.out.println("生成的SHA-512摘要数据:"+new String(resBuff));
53 //*********************************************************************************
54 //DES测试(加密)
55 //添加新安全算法,如果用JCE就要把它添加进去
56 Security.addProvider(new com.sun.crypto.provider.SunJCE());
57 DesEncrypt desEncrypt = new DesEncrypt();
58 key = "11111111";
59 desEncrypt.setAlgorithm("DES");
60 desEncrypt.setKey(key.getBytes());
61 desEncrypt.setOther("DES/ECB/NoPadding".getBytes());
62 desEncrypt.setEncodeMode(2);
63 resBuff = desEncrypt.buildData(buff);
64 System.out.println("DES加密后的数据:"+new String(resBuff));
65 //DES测试(解密)
66 DesDecrypt desDecrypt = new DesDecrypt();
67 desDecrypt.setAlgorithm("DES");
68 desDecrypt.setKey(key.getBytes());
69 desDecrypt.setOther("DES/ECB/NoPadding".getBytes());
70 desDecrypt.setEncodeMode(2);
71 resBuff = desDecrypt.buildData(resBuff);
72 System.out.println("DES解密后的数据:"+new String(resBuff));
73 //*********************************************************************************
74 //3DES测试(加密)
75 key = "111111112222222211111111";
76 desEncrypt.setAlgorithm("DESede");
77 desEncrypt.setKey(key.getBytes());
78 desEncrypt.setOther("DESede/ECB/NoPadding".getBytes());
79 desEncrypt.setEncodeMode(2);
80 resBuff = desEncrypt.buildData(buff);
81 System.out.println("3DES加密后的数据:"+new String(resBuff));
82 //3DES测试(解密)
83 key = "111111112222222211111111";
84 desDecrypt.setAlgorithm("DESede");
85 desDecrypt.setKey(key.getBytes());
86 desDecrypt.setOther("DESede/ECB/NoPadding".getBytes());
87 desDecrypt.setEncodeMode(2);
88 resBuff = desDecrypt.buildData(resBuff);
89 System.out.println("3DES解密后的数据:"+new String(resBuff));
90 //*********************************************************************************
91 //AES测试(加密)
92 key = "1111111122222222";
93 desEncrypt.setAlgorithm("AES");
94 desEncrypt.setKey(key.getBytes());
95 desEncrypt.setOther("AES/ECB/NoPadding".getBytes());
96 desEncrypt.setEncodeMode(2);
97 resBuff = desEncrypt.buildData(buff);
98 System.out.println("AES加密后的数据:"+new String(resBuff));
99 //AES测试(解密)
100 key = "1111111122222222";
101 desDecrypt.setAlgorithm("AES");
102 desDecrypt.setKey(key.getBytes());
103 desDecrypt.setOther("AES/ECB/NoPadding".getBytes());
104 desDecrypt.setEncodeMode(2);
105 resBuff = desDecrypt.buildData(resBuff);
106 System.out.println("AES解密后的数据:"+new String(resBuff));
107 //*********************************************************************************
108 //RSA测试(加密)
109 buff = "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456".getBytes();
110 String certFile = "D://TestCert.pfx";
111 String certPass = "1111";
112
113 RsaPublicEncrypt rsaPublicEncrypt = new RsaPublicEncrypt(certFile,certPass);
114 RsaPrivateEncrypt rsaPrivateEncrypt = new RsaPrivateEncrypt(certFile,certPass);
115 rsaPublicEncrypt.setEncodeMode(2);
116 rsaPrivateEncrypt.setEncodeMode(2);
117 byte[] pubEncryptBuff = rsaPublicEncrypt.buildData(buff);
118 System.out.println("RSA公钥加密后的数据:"+new String(pubEncryptBuff));
119 byte[] priEncryptBuff = rsaPrivateEncrypt.buildData(buff);
120 System.out.println("RSA私钥加密后的数据:"+new String(priEncryptBuff));
121 rsaPrivateEncrypt.setAlgorithm("MD5withRSA");
122 byte[] signEncryptBuff = rsaPrivateEncrypt.buildSignData(buff);
123 System.out.println("RSA签名后的数据:"+new String(signEncryptBuff));
124 //RSA测试(解密)
125 RsaPublicDecrypt rsaPublicDecrypt = new RsaPublicDecrypt(certFile,certPass);
126 RsaPrivateDecrypt rsaPrivateDecrypt = new RsaPrivateDecrypt(certFile,certPass);
127 rsaPublicDecrypt.setEncodeMode(2);
128 rsaPrivateDecrypt.setEncodeMode(2);
129 byte[] pubDecryptBuff = rsaPublicDecrypt.buildData(priEncryptBuff);
130 System.out.println("RSA公钥解密后的数据:"+new String(pubDecryptBuff));
131 byte[] priDecryptBuff = rsaPrivateDecrypt.buildData(pubEncryptBuff);
132 System.out.println("RSA私钥解密后的数据:"+new String(priDecryptBuff));
133 rsaPublicDecrypt.setAlgorithm("MD5withRSA");
134 boolean signFlag = rsaPublicDecrypt.verifySignData(buff, signEncryptBuff);
135 System.out.println("RSA验签的结果:"+signFlag);
136 //*********************************************************************************
137 } catch(Exception e) {
138 e.printStackTrace();
139 }
140 }
141 }

这样,RSA的解密也算是实现了。

 

以上几篇文章主要对一般常的几种算法MD5、SHA1、DES、RSA进行实现,有不合理的地方请大家指出,我会改进,我会将源代码上传到上面供大家下载。

JAVA数据摘要加密解密源程序

转载于:https://www.cnblogs.com/ynjxxk/archive/2012/03/30/2425642.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值