基于Java的 hash(MD5,SHA1),对称加密算法(DES,AES),非对称加密算法(RSA),数字签名,客户端摘要的实现

public static byte[] getMD5(String content) throws Exception
	{
		MessageDigest md = MessageDigest.getInstance("MD5");
		byte[] bytes = md.digest(content.getBytes("utf8"));
		return bytes;
	}
//MD5 Message Digest Algorithm 5(128位) 返回String的一中实现 ,也可以用Base64
	public static String testMD5(String content) throws Exception
	{
		MessageDigest md = MessageDigest.getInstance("MD5");
		byte[] bytes = md.digest(content.getBytes("utf8"));
		return bytes_String16(bytes);
	}
//SHA Secure Hash Algorithm (160位)
	public static String testSHA1(String content) throws Exception
	{
		MessageDigest md = MessageDigest.getInstance("SHA-1");
		byte[] bytes = md.digest(content.getBytes("utf8"));
		return byte2hex(bytes);
	}
/**
	* byte[] 转16进制字符串
	* @param b
	* @return
	*/
	public static String bytes_String16(byte[] b) {
	    char[] _16 = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
	    StringBuilder sb = new StringBuilder();
		for(int i = 0 ; i<b.length;i++) {
		    sb.append(_16[b[i]>>4&0xf])
	        .append(_16[b[i]&0xf]);
	    }
	    return sb.toString();
	}
//字节数组转成16进制
	private static String byte2hex(byte[] bytes)
	{
		StringBuilder hex = new StringBuilder();
		for(int i=0;i<bytes.length;i++)
		{
			byte b = bytes[i];
			boolean negative = false;
			if(b<0) negative = true;
			int inte = Math.abs(b);
			if(negative) inte = inte | 0x80;
			String temp = Integer.toHexString(inte & 0xFF);
			if(temp.length()==1)
			{
				hex.append("0");
			}
			hex.append(temp.toLowerCase());
		}
		return hex.toString();
	}
	//16进制转成字节数组
	private static byte[] hex2bytes(String hex)
	{
		byte[] bytes = new byte[hex.length()/2];
		for(int i=0;i<hex.length();i=i+2)
		{
			String subStr = hex.substring(i,i+2);
			boolean negative = false;
			int inte = Integer.parseInt(subStr,16);
			if(inte>127) negative = true;
			if(inte == 128)
			{
				inte = -128;
			}
			else if(negative)
			{
				inte = 0-(inte & 0x7F);
			}
			byte b = (byte)inte;
			bytes[i/2] = b;
		}
		return bytes;
	}	
//Base64 编码 是一种基于64个可打印字符来表示二进制数据的方法
	private static String byte2base64(byte[] bytes)
	{
		BASE64Encoder  base64Encoder = new BASE64Encoder();
		return base64Encoder.encode(bytes);
	}
	private static byte[] base642byte(String base64) throws IOException
	{
		BASE64Decoder base64Decoder = new BASE64Decoder();
		return base64Decoder.decodeBuffer(base64);
	}

/**
     * 对称加密算法  常用的对称加密算法 有 DES,3DES,AES
     * DES: 明文按64位进行分组,密钥长64位 实际上只有56位参与运算
     * 3DES:是DES向AES过度的加密算法 使用3条56位的密钥对数据进行3次加密 是DES的一个更安全的变形
     */

//生成DES密钥 并且编码成base64字符串
	public static String genKeyDES() throws Exception
	{
		KeyGenerator keyGen = KeyGenerator.getInstance("DES");
		keyGen.init(56);
		SecretKey key = keyGen.generateKey();
		String base64Str = byte2base64(key.getEncoded());
		return base64Str;
	}
	//base64字符串展开成真实的16进制密钥  
	public static SecretKey loadKeyDES(String base64Key) throws Exception
	{
		byte[] bytes = base642byte(base64Key);
		SecretKey key = new SecretKeySpec(bytes, "DES");
		return key;
	}

//加密函数
    /**
     * 
     * @param 要加密的字节数组
     * @param 16进制形式的密钥
     * @return  加密完成的字节数组
     * @throws Exception
     */

public static byte[] encryptDES(byte[] source,SecretKey key) throws Exception
	{
		Cipher cipher = Cipher.getInstance("DES");
		cipher.init(cipher.ENCRYPT_MODE, key);  //和下面的模式是不一样
		byte[] bytes = cipher.doFinal(source);
		return bytes;
	}

/**
     * 
     * @param 要解密的字节数组
     * @param 16进制加密的密钥
     * @return  解密后的字节数组
     * @throws Exception
     */

public static byte[] decryptDES(byte[] source,SecretKey key) throws Exception
	{
		Cipher cipher = Cipher.getInstance("DES");
		cipher.init(cipher.DECRYPT_MODE, key);
		byte[] bytes = cipher.doFinal(source);
		return bytes;
	}

/**
     * AES Advanced Encryption Standard 这个标准用来取代原先的DES算法,是最为流行算法之一
     * 设计有三个密钥长度(128,192,256位)比DES算法加密强度更高,更为安全
     * 
     */

//产生一个base64编码的密钥
	public static String genKeyAES() throws Exception
	{
		KeyGenerator keyGen = KeyGenerator.getInstance("AES");
		keyGen.init(256); //普通的128位可以使用  192,256位会报错
		//https://stackoverflow.com/questions/6481627/java-security-illegal-key-size-or-default-parameters
		//local_policy.jar  US_export_policy.jar  覆盖掉 C:\Program Files\Java\jre1.8.0_111\lib\security
		SecretKey key = keyGen.generateKey();
		String base64Str = byte2base64(key.getEncoded());
		return base64Str;
	}
	//base64编码的转换成真实的16进制密钥
	public static SecretKey loadKeyAES(String base64Key) throws Exception
	{
		byte[] bytes = base642byte(base64Key);
		SecretKey key = new SecretKeySpec(bytes, "AES");
		return key;
	}
	//加密
	public static byte[] encryptAES(byte[] source,SecretKey key) throws Exception
	{
		Cipher cipher = Cipher.getInstance("AES");
		cipher.init(cipher.ENCRYPT_MODE, key);
		byte[] bytes = cipher.doFinal(source);
		return bytes;
	}
	//解密
	public static byte[] decryptAES(byte[] source,SecretKey key) throws Exception
	{
		Cipher cipher = Cipher.getInstance("AES");
		cipher.init(cipher.DECRYPT_MODE, key);
		byte[] bytes = cipher.doFinal(source);
		return bytes;
	}

/**
     * 非对称加密算法 又称公开密钥加密算法,有两个密钥 一个是公钥(publickey) 另一个是私钥(privatekey)
     * 公钥和私钥要配对使用,如果公钥对数据加密,只有用对应的私钥解密,而如果用私钥对数据加密,只能用对应的公钥进行解密
     * 基本过程  甲方生成一对密钥 并将其中一把作为公钥向其他人公开,得到公钥的乙方使用该密钥对信息进行加密后在发送给甲方,甲方使用
     * 自己的私钥进行解密
     * 非对称加密算法能够保证 即使获知公钥,加密算法,加密算法源代码的情况下也无法获得 公钥对应的私钥,也无法对密文进行解密
     * 缺点:速度慢  对称加密较长的文件,然后用非对称机密算法给文件密钥加密
     * 最广泛的非对称加密算法 是RSA
     * RAS 基于数论:将两个大素数相乘容易,对乘积进行因式分解十分困难,乘积公开作为加密密钥
     * 
     */

//获得乘积因子
	 public static KeyPair getKeyPair() throws Exception
	 {
		 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
		 keyPairGenerator.initialize(2048);
		 KeyPair keyPair = keyPairGenerator.generateKeyPair();
		 return keyPair;
	 }
	 //公钥base64编码
	 public static String getPublicKey(KeyPair keyPair)
	 {
		 PublicKey publicKey = keyPair.getPublic();
		 byte[] bytes = publicKey.getEncoded();
		 return byte2base64(bytes);
	 }
	//私钥base64编码
	 public static String getPrivateKey(KeyPair keyPair)
	 {
		 PrivateKey privateKey = keyPair.getPrivate();
		 byte[] bytes = privateKey.getEncoded();
		 return byte2base64(bytes);
	 }
	 //base64类型转换成PublicKey
	 public static PublicKey string2PublicKey(String pubStr) throws Exception
	 {
		 byte[] keyBytes = base642byte(pubStr);
		 /**
		  * This class represents the ASN.1 encoding of a public key,
		  * encoded accroding to the ASN.1 type
		  * 此类表示公钥的ASN.1编码,根据ASN.1类型进行编码
		  */
		 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
		 KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		 PublicKey publicKey = keyFactory.generatePublic(keySpec);
		 return publicKey;
	 }
	 //base64生成PrivateKey
	 public static PrivateKey string2PrivateKey(String priStr) throws Exception
	 {
		 byte[] keyBytes = base642byte(priStr);
		 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
		 KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		 PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
		 return privateKey;
	 }
	 //使用公钥加密字节数组
	 public static byte[] publicEncrypt(byte[] content,PublicKey publicKey) throws Exception
	 {
		 Cipher cipher = Cipher.getInstance("RSA");
		 cipher.init(cipher.ENCRYPT_MODE, publicKey);
		 byte[] bytes = cipher.doFinal(content);
		 return bytes;
	 }
	//使用私钥加密字节数组
	 public static byte[] privateEncrypt(byte[] content,PrivateKey privateKey) throws Exception
	 {
		 Cipher cipher = Cipher.getInstance("RSA");
		 cipher.init(cipher.ENCRYPT_MODE, privateKey);
		 byte[] bytes = cipher.doFinal(content);
		 return bytes;
	 }
	 //使用私钥解密字节数组
	 public static byte[] privateDecrypt(byte[] content,PrivateKey privateKey) throws Exception
	 {
		 Cipher cipher = Cipher.getInstance("RSA");
		 cipher.init(cipher.DECRYPT_MODE, privateKey);
		 byte[] bytes = cipher.doFinal(content);
		 return bytes;
	 }
	//使用公钥解密字节数组
	 public static byte[] publicDecrypt(byte[] content,PublicKey publicKey) throws Exception
	 {
		 Cipher cipher = Cipher.getInstance("RSA");
		 cipher.init(cipher.DECRYPT_MODE, publicKey);
		 byte[] bytes = cipher.doFinal(content);
		 return bytes;
	 }

/**
      * 数字签名是非对称加密算法与数字摘要技术的综合应用,通信内容的摘要信息使用发送者的私钥进行加密,然后将密文与原文一起传输给信息的接受者
      * 接受者通过使用与发送者相同的摘要算法解密被加密的摘要信息,然后对通信内容采用相同的hash算法得到摘要串,在和解密的比较
      * 相同证明中途没有被改 常见的数字签名算法有
      * MD5withRSA,SHA1withRSA 
      * 
      */

//MD5withRSA
	private static byte[] sign(byte[] content,PrivateKey privateKey) throws Exception
	{
		MessageDigest md = MessageDigest.getInstance("MD5");
		byte[] bytes = md.digest(content);
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(cipher.ENCRYPT_MODE, privateKey);
		byte[] encryptBytes = cipher.doFinal(bytes);
		return encryptBytes;
	}
	//认证
	private static boolean verify(byte[] content,byte[] sign,PublicKey publicKey) throws Exception
	{
		MessageDigest md = MessageDigest.getInstance("MD5");
		byte[] bytes = md.digest(content);
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(cipher.DECRYPT_MODE, publicKey);
		byte[] decryptBytes = cipher.doFinal(sign);
		if(byte2base64(decryptBytes).equals(byte2base64(bytes)))
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	
	//java 自带的API
	private static byte[] signApi(byte[] content,PrivateKey privateKey) throws Exception
	{
		Signature signature = Signature.getInstance("MD5withRSA");
		signature.initSign(privateKey);
		signature.update(content);
		return signature.sign();
	}
	//
	private static boolean verifyApi(byte[] content,byte[] sign,PublicKey publicKey) throws Exception
	{
		Signature signature = Signature.getInstance("MD5withRSA");
		signature.initVerify(publicKey);
		signature.update(content);
		return signature.verify(sign);
	}

/**
     * SHA1withRSA和上面的类似 ,改下参数就可以了
     * 
     */

/**
     * 摘要认证的实现
     * 请求参数->参数排序->将参数串接起来加上secret 生成带摘要字符串->使用MD5算法生成摘要串
     */

private static String getDigest(Map<String, String> params) throws Exception
	{
		String secret = "abcdefjijklmn";
		Set<String> keySet = params.keySet();
		//使用Treeset排序
		TreeSet<String> sortSet = new TreeSet<String>();
		sortSet.addAll(keySet);
		String keyvalueStr = "";
		Iterator<String> it = sortSet.iterator();
		while(it.hasNext())
		{
			String key = it.next();
			String value = params.get(key);
			keyvalueStr += key + value;
		}
		keyvalueStr += secret;
		String base64Str = byte2base64(getMD5(keyvalueStr));
		return base64Str;
	}
	//java服务端参数摘要校验
	private static boolean validate(Map params,String digest) throws Exception
	{
		String secret = "abcdefjijklmn";
		Set<String> keySet = params.keySet();
		//treeset sort
		TreeSet<String> sortSet = new TreeSet<String>();
		sortSet.addAll(keySet);
		String keyvalueStr = "";
		Iterator<String> it = sortSet.iterator();
		while(it.hasNext())
		{
			String key = it.next();
			String values = (String) params.get(key);
			keyvalueStr += key + values;
		}
		keyvalueStr += secret;
		String base64Str = byte2base64(getMD5(keyvalueStr));
		if(base64Str.equals(digest))
		{
			return true;
		}
		else
		{
			return false;
		}
	}

函数的测试

String str = "大时代撒多撒多撒多撒多撒多";
		String bufferMD5 = testMD5(str);
		String bufferSHA1 = testSHA1(str);
		System.out.println(bufferMD5); //4C82B120D0926916A9F4E3554DE555B2
		System.out.println(bufferSHA1);//1A11F3E193C78A9073C872FFCAB455CD24AFC2FB
		//DES加密
		String strbase64DES = genKeyDES();
		System.out.println("v+P+bsJeq48=");  //v+P+bsJeq48=
		SecretKey keyDES = loadKeyDES("v+P+bsJeq48=");
		//将str 转成字节数组(以utf-8的形式)
		byte[] byte_UTF = str.getBytes("UTF-8");
		System.out.println(Arrays.toString(byte_UTF));  //[-26, -99, -88, -27, -80, -111, -27, -82, -66]
		//加密
		byte[] byte_DES = encryptDES(byte_UTF, keyDES);
		System.out.println(Arrays.toString(byte_DES));  //[-104, 114, 21, -67, -31, 34, -89, 13, -120, -4, 1, -82, 55, 86, 122, -102]
		//密文用base64编码
		String str_BASE = byte2base64(byte_DES); //mHIVveEipw2I/AGuN1Z6mg==
		System.out.println(str_BASE);  
		//base64解码
		byte[] byte_EDES = base642byte(str_BASE);  // [-104, 114, 21, -67, -31, 34, -89, 13, -120, -4, 1, -82, 55, 86, 122, -102]
		System.out.println(Arrays.toString(byte_EDES));
		//解密
		byte[] byte_EUTF = decryptDES(byte_DES, keyDES);
		System.out.println(Arrays.toString(byte_EUTF)); //[-26, -99, -88, -27, -80, -111, -27, -82, -66]
		//byte 转换成string
		String str_E = new String(byte_EUTF,"UTF-8");
		System.out.println(str_E);

AES测试

//AES加密
		String strbase64AES = genKeyAES();
		System.out.println(strbase64AES);  //6ZNeCtWgEyiyKXYrc6R3OA==     128位
										  // Zbn02vN5nsZ0qoUmJq+H6GJehQozq5pw  192位
										  // BOoz7HVmZVBrS7OHVdZ2HHFfb6FRxyNmCWhXnefKv0M=  256位
		SecretKey keyAES = loadKeyAES(strbase64AES);
		//将str 转成字节数组(以utf-8的形式)
		byte[] byte_UTF = str.getBytes("UTF-8");
		System.out.println(Arrays.toString(byte_UTF));  //[-26, -99, -88, -27, -80, -111, -27, -82, -66]
		//加密
		byte[] byte_AES = encryptAES(byte_UTF, keyAES);
		System.out.println(Arrays.toString(byte_AES));  //[73, -22, -3, -10, -115, -95, 107, -103, 117, 45, 60, 9, 81, -74, 13, -80]
		//密文用base64编码
		String str_BASE = byte2base64(byte_AES); //Ser99o2ha5l1LTwJUbYNsA==
		System.out.println(str_BASE);  
		//base64解码
		byte[] byte_EAES = base642byte(str_BASE);  // [73, -22, -3, -10, -115, -95, 107, -103, 117, 45, 60, 9, 81, -74, 13, -80]
		System.out.println(Arrays.toString(byte_EAES));
		//解密
		byte[] byte_EUTF = decryptAES(byte_EAES, keyAES);
		System.out.println(Arrays.toString(byte_EUTF)); //[-26, -99, -88, -27, -80, -111, -27, -82, -66]
		//byte 转换成string
		String str_E = new String(byte_EUTF,"UTF-8");
		System.out.println(str_E);

RSA测试

//RSA 加密
		KeyPair keyPair = getKeyPair();
		String strbase64RSA_public = getPublicKey(keyPair);
		System.out.println(strbase64RSA_public);  //MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALC2WJe6+0pPLkuttnxGnDGGTJ2MNLz1dFZh0GrkoZrC
												  //QwQF5lflatfj5TtGJTufm4hMQE5tuqa69N99jSUeciUCAwEAAQ==   768位
		String strbase64RSA_private = getPrivateKey(keyPair);
		System.out.println(strbase64RSA_private); //MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAsLZYl7r7Sk8uS622fEacMYZMnYw0
//													vPV0VmHQauShmsJDBAXmV+Vq1+PlO0YlO5+biExATm26prr0332NJR5yJQIDAQABAkAOrzhxc2JK
//													bIYGV+sgLKXyH5ziQrJnOWZvfzVYjKM5PuQDKTsHJxhu+RRSAx200qdg6vVijnTMpv5itztUQIXB
//													AiEA2WjxujvzguNPeR+Bq4jF08l0kdyRBc401l6vHGTb0PkCIQDQFBw/pWM2XByuhmfihu3jyCJQ
//													dCA9HSnvyrgoMk5hjQIgTtEz6S84zbe4pRGeAeDYzznWj9aloLQsBZdX5nROGIkCH3+b1bcytqWf
//													1/cwdoV2Om53TpQIo7zXJeDpcgc00t0CIQCEtxfeZCk4aciKiNubjYOdFKX7stFKfqFlLlwxfs3b
//													yQ==
//		//获取public 和 private 对象
		PublicKey publicKey = string2PublicKey(strbase64RSA_public);
		PrivateKey privateKey = string2PrivateKey(strbase64RSA_private);

		//将str 转成字节数组(以utf-8的形式)
		byte[] byte_UTF = str.getBytes("UTF-8");  //512位 RSA 最多加密字节数:512/8-11=53 字节  1024位  117字节  2048位 245字节
		System.out.println(Arrays.toString(byte_UTF));  //[-26, -99, -88, -27, -80, -111, -27, -82, -66]
		//公钥加密
		//byte[] byte_RSA = publicEncrypt(byte_UTF, publicKey);
		//私钥加密
		byte[] byte_RSA = privateEncrypt(byte_UTF, privateKey);
		System.out.println(Arrays.toString(byte_RSA));  //[11, 7, -64, 21, -106, -28, -3, -24, 102, 84, -58, -43, -126, -119, 103, -102, 79, 65, -118, -27, -4, -35, 120, 54, 114, 30, -32, -89, -60, -59, 81, 86, 84, 94, 119, -6, -104, 81, 124, -32, 92, -3, 123, -89, 38, -112, 123, -16, 106, 20, 14, -74, -58, -12, 60, 101, -86, -7, 22, -26, 23, 10, -62, -73]
		//密文用base64编码
		String str_BASE = byte2base64(byte_RSA); //CwfAFZbk/ehmVMbVgolnmk9BiuX83Xg2ch7gp8TFUVZUXnf6mFF84Fz9e6cmkHvwahQOtsb0PGWq
//												   +RbmFwrCtw==  密文不随明文长度变化  528位
		System.out.println(str_BASE);  
		//base64解码
		byte[] byte_ERSA = base642byte(str_BASE);  // [73, -22, -3, -10, -115, -95, 107, -103, 117, 45, 60, 9, 81, -74, 13, -80]
		System.out.println(Arrays.toString(byte_ERSA));
		//私钥解密
		//byte[] byte_EUTF = privateDecrypt(byte_ERSA, privateKey);
		//公钥解密
		byte[] byte_EUTF = publicDecrypt(byte_ERSA, publicKey);
		System.out.println(Arrays.toString(byte_EUTF)); //[-26, -99, -88, -27, -80, -111, -27, -82, -66]
		//byte 转换成string
		String str_E = new String(byte_EUTF,"UTF-8");
		System.out.println(str_E);

MD5withRSA测试

//MD5withRSA验证
		KeyPair keyPair = getKeyPair();
		String strbase64RSA_public = getPublicKey(keyPair);
		System.out.println(strbase64RSA_public); 
		String strbase64RSA_private = getPrivateKey(keyPair);
		System.out.println(strbase64RSA_private); 
		PublicKey publicKey = string2PublicKey(strbase64RSA_public);
		PrivateKey privateKey = string2PrivateKey(strbase64RSA_private);
		byte[] byte_UTF = str.getBytes("UTF-8"); 
		System.out.println(Arrays.toString(byte_UTF)); 
		//摘要加密
		//byte[] byteMD5withRSA = sign(byte_UTF, privateKey);
		//APi
		byte[] byteMD5withRSA = signApi(byte_UTF, privateKey);
		System.out.println(Arrays.toString(byteMD5withRSA));
		//API
		//boolean flag = verify(byte_UTF, byteMD5withRSA, publicKey);
		boolean flag = verifyApi(byte_UTF, byteMD5withRSA, publicKey);
		System.out.println(flag);

客户端参数摘要

Map<String, String> params = new HashMap<String,String>();
		params.put("controller", "Home");
		params.put("Action", "Index");
		params.put("Id", "454");
		params.put("Name", "张三");
		String str_params = getDigest(params);
		System.out.println(str_params);
		boolean flag = validate(params, str_params);
		System.out.println(flag);

需要导入的jar包

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.InvalidParameterException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.MacSpi;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import sun.security.rsa.RSASignature.MD5withRSA;

有什么问题欢迎指正!!

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值