Java实现国密算法SM2,SM3,SM4,并且实现ECB和CBC模式

数据加密算法之国密SM4、SM3、SM2研究及Java实现 国密加密算法研究 阅读详情

代码中实现了电码本ECB模式和密文分组连接CBC模式,SM3.java和SM4.java为算法实现类,utils的都是根据实现类写的工具,可以根据需要调用杂凑算法SM3的杂凑功能获得杂凑值。

SM4.java中

sm4_crypt_ecb(SM4_Context ctx, byte[] input)      ECB模式加解密方法,根据密钥判断加解密功能

sm4_crypt_cbc(SM4_Context ctx, byte[] iv, byte[] input)      CBC模式加解密方法,根据密钥判断加解密功能

加密解密通过如下方法:

sm4_setkey_enc(SM4_Context ctx, byte[] key)  设置加密密钥调用上述方法,实现加密

sm4_setkey_dec(SM4_Context ctx, byte[] key)  设置解密密钥调用上述方法,实现解密

需要导入的包为bcprov-jdk16  我用的版本是bcprov-jdk16-1.46

maven中配置依赖:

<dependency>
	<groupId>org.bouncycastle</groupId>
	<artifactId></artifactId>
	<version>1.46</version>
</dependency>

package中class目录如下:

chiper.java

import java.math.BigInteger;  
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;  
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;  
import org.bouncycastle.crypto.params.ECPublicKeyParameters;  
import org.bouncycastle.math.ec.ECPoint; 

public class Cipher {
	 private int ct;  
	    private ECPoint p2;  
	    private SM3Digest sm3keybase;  
	    private SM3Digest sm3c3;  
	    private byte key[];  
	    private byte keyOff;  
	  
	    public Cipher()   
	    {  
	        this.ct = 1;  
	        this.key = new byte[32];  
	        this.keyOff = 0;  
	    }  
	  
	    private void Reset()   
	    {  
	        this.sm3keybase = new SM3Digest();  
	        this.sm3c3 = new SM3Digest();  
	          
	        byte p[] = Util.byteConvert32Bytes(p2.getX().toBigInteger());  
	        this.sm3keybase.update(p, 0, p.length);  
	        this.sm3c3.update(p, 0, p.length);  
	          
	        p = Util.byteConvert32Bytes(p2.getY().toBigInteger());  
	        this.sm3keybase.update(p, 0, p.length);  
	        this.ct = 1;  
	        NextKey();  
	    }  
	  
	    private void NextKey()   
	    {  
	        SM3Digest sm3keycur = new SM3Digest(this.sm3keybase);  
	        sm3keycur.update((byte) (ct >> 24 & 0xff));  
	        sm3keycur.update((byte) (ct >> 16 & 0xff));  
	        sm3keycur.update((byte) (ct >> 8 & 0xff));  
	        sm3keycur.update((byte) (ct & 0xff));  
	        sm3keycur.doFinal(key, 0);  
	        this.keyOff = 0;  
	        this.ct++;  
	    }  
	  
	    public ECPoint Init_enc(SM2 sm2, ECPoint userKey)   
	    {  
	        AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();  
	        ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();  
	        ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();  
	        BigInteger k = ecpriv.getD();  
	        ECPoint c1 = ecpub.getQ();  
	        this.p2 = userKey.multiply(k);  
	        Reset();  
	        return c1;  
	    }  
	  
	    public void Encrypt(byte data[])   
	    {  
	        this.sm3c3.update(data, 0, data.length);  
	        for (int i = 0; i < data.length; i++)   
	        {  
	            if (keyOff == key.length)  
	            {  
	                NextKey();  
	            }  
	            data[i] ^= key[keyOff++];  
	        }  
	    }  
	  
	    public void Init_dec(BigInteger userD, ECPoint c1)  
	    {  
	        this.p2 = c1.multiply(userD);  
	        Reset();  
	    }  
	  
	    public void Decrypt(byte data[])   
	    {  
	        for (int i = 0; i < data.length; i++)  
	        {  
	            if (keyOff == key.length)  
	            {  
	                NextKey();  
	            }  
	            data[i] ^= key[keyOff++];  
	        }  
	  
	        this.sm3c3.update(data, 0, data.length);  
	    }  
	  
	    public void Dofinal(byte c3[])   
	    {  
	        byte p[] = Util.byteConvert32Bytes(p2.getY().toBigInteger());  
	        this.sm3c3.update(p, 0, p.length);  
	        this.sm3c3.doFinal(c3, 0);  
	        Reset();  
	    }  
}

SM2.java

import java.math.BigInteger;  
import java.security.SecureRandom;  
  
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;  
import org.bouncycastle.crypto.params.ECDomainParameters;  
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;  
import org.bouncycastle.math.ec.ECCurve;  
import org.bouncycastle.math.ec.ECFieldElement;  
import org.bouncycastle.math.ec.ECPoint;  
import org.bouncycastle.math.ec.ECFieldElement.Fp;  

public class SM2 {
	 //测试参数  
//  public static final String[] ecc_param = {  
//      "8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3",   
//      "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498",   
//      "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A",   
//      "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7",   
//      "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D",   
//      "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2"   
//  };  
      
    //正式参数  
    public static String[] ecc_param = {   
        "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF",  
        "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",  
        "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",  
        "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",  
        "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",  
        "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"  
    };  
  
    public static SM2 Instance()   
    {  
        return new SM2();  
    }  
  
    public final BigInteger ecc_p;  
    public final BigInteger ecc_a;  
    public final BigInteger ecc_b;  
    public final BigInteger ecc_n;  
    public final BigInteger ecc_gx;  
    public final BigInteger ecc_gy;  
    public final ECCurve ecc_curve;  
    public final ECPoint ecc_point_g;  
    public final ECDomainParameters ecc_bc_spec;  
    public final ECKeyPairGenerator ecc_key_pair_generator;  
    public final ECFieldElement ecc_gx_fieldelement;  
    public final ECFieldElement ecc_gy_fieldelement;  
  
    public SM2()   
    {  
        this.ecc_p = new BigInteger(ecc_param[0], 16);  
        this.ecc_a = new BigInteger(ecc_param[1], 16);  
        this.ecc_b = new BigInteger(ecc_param[2], 16);  
        this.ecc_n = new BigInteger(ecc_param[3], 16);  
        this.ecc_gx = new BigInteger(ecc_param[4], 16);  
        this.ecc_gy = new BigInteger(ecc_param[5], 16);  
  
        this.ecc_gx_fieldelement = new Fp(this.ecc_p, this.ecc_gx);  
        this.ecc_gy_fieldelement = new Fp(this.ecc_p, this.ecc_gy);  
  
        this.ecc_curve = new ECCurve.Fp(this.ecc_p, this.ecc_a, this.ecc_b);  
        this.ecc_point_g = new ECPoint.Fp(this.ecc_curve, this.ecc_gx_fieldelement, this.ecc_gy_fieldelement);  
  
        this.ecc_bc_spec = new ECDomainParameters(this.ecc_curve, this.ecc_point_g, this.ecc_n);  
  
        ECKeyGenerationParameters ecc_ecgenparam;  
        ecc_ecgenparam = new ECKeyGenerationParameters(this.ecc_bc_spec, new SecureRandom());  
  
        this.ecc_key_pair_generator = new ECKeyPairGenerator();  
        this.ecc_key_pair_generator.init(ecc_ecgenparam);  
    }  
}

SM2Utils.java

import java.io.IOException;  
import java.math.BigInteger;  
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;  
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;  
import org.bouncycastle.crypto.params.ECPublicKeyParameters;  
import org.bouncycastle.math.ec.ECPoint; 

public class SM2Utils {
	  //生成随机秘钥对  
    public static void generateKeyPair(){  
        SM2 sm2 = SM2.Instance();  
        AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();  
        ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();  
        ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();  
        BigInteger privateKey = ecpriv.getD();  
        ECPoint publicKey = ecpub.getQ();  
          
        System.out.println("公钥: " + Util.byteToHex(publicKey.getEncoded()));  
        System.out.println("私钥: " + Util.byteToHex(privateKey.toByteArray()));  
    }  
      
    //数据加密  
    public static String encrypt(byte[] publicKey, byte[] data) throws IOException  
    {  
        if (publicKey == null || publicKey.length == 0)  
        {  
            return null;  
        }  
          
        if (data == null || data.length == 0)  
        {  
            return null;  
        }  
          
        byte[] source = new byte[data.length];  
        System.arraycopy(data, 0, source, 0, data.length);  
          
        Cipher cipher = new Cipher();  
        SM2 sm2 = SM2.Instance();  
        ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);  
          
        ECPoint c1 = cipher.Init_enc(sm2, userKey);  
        cipher.Encrypt(source);  
        byte[] c3 = new byte[32];  
        cipher.Dofinal(c3);  
          
//      System.out.println("C1 " + Util.byteToHex(c1.getEncoded()));  
//      System.out.println("C2 " + Util.byteToHex(source));  
//      System.out.println("C3 " + Util.byteToHex(c3));  
        //C1 C2 C3拼装成加密字串  
        return Util.byteToHex(c1.getEncoded()) + Util.byteToHex(source) + Util.byteToHex(c3);  
          
    }  
      
    //数据解密  
    public static byte[] decrypt(byte[] privateKey, byte[] encryptedData) throws IOException  
    {  
        if (privateKey == null || privateKey.length == 0)  
        {  
            return null;  
        }  
          
        if (encryptedData == null || encryptedData.length == 0)  
        {  
            return null;  
        }  
        //加密字节数组转换为十六进制的字符串 长度变为encryptedData.length * 2  
        String data = Util.byteToHex(encryptedData);  
        /***分解加密字串 
         * (C1 = C1标志位2位 + C1实体部分128位 = 130) 
         * (C3 = C3实体部分64位  = 64) 
         * (C2 = encryptedData.length * 2 - C1长度  - C2长度) 
         */  
        byte[] c1Bytes = Util.hexToByte(data.substring(0,130));  
        int c2Len = encryptedData.length - 97;  
        byte[] c2 = Util.hexToByte(data.substring(130,130 + 2 * c2Len));  
        byte[] c3 = Util.hexToByte(data.substring(130 + 2 * c2Len,194 + 2 * c2Len));  
          
        SM2 sm2 = SM2.Instance();  
        BigInteger userD = new BigInteger(1, privateKey);  
          
        //通过C1实体字节来生成ECPoint  
        ECPoint c1 = sm2.ecc_curve.decodePoint(c1Bytes);  
        Cipher cipher = new Cipher();  
        cipher.Init_dec(userD, c1);  
        cipher.Decrypt(c2);  
        cipher.Dofinal(c3);  
          
        //返回解密结果  
        return c2;  
    }  
      
    public static void main(String[] args) throws Exception   
    {  
        //生成密钥对  
        generateKeyPair();  
          
        String plainText = "ererfeiisgod";  
        byte[] sourceData = plainText.getBytes();  
          
        //下面的秘钥可以使用generateKeyPair()生成的秘钥内容  
        // 国密规范正式私钥  
        String prik = "3690655E33D5EA3D9A4AE1A1ADD766FDEA045CDEAA43A9206FB8C430CEFE0D94";  
        // 国密规范正式公钥  
        String pubk = "04F6E0C3345AE42B51E06BF50B98834988D54EBC7460FE135A48171BC0629EAE205EEDE253A530608178A98F1E19BB737302813BA39ED3FA3C51639D7A20C7391A";  
          
        System.out.println("加密: ");  
        String cipherText = SM2Utils.encrypt(Util.hexToByte(pubk), sourceData);  
        System.out.println(cipherText);  
        System.out.println("解密: ");  
        plainText = new String(SM2Utils.decrypt(Util.hexToByte(prik), Util.hexToByte(cipherText)));  
        System.out.println(plainText);  
          
    }  
}

SM3.java

public class SM3 {
	 public static final byte[] iv = { 0x73, (byte) 0x80, 0x16, 0x6f, 0x49,  
		        0x14, (byte) 0xb2, (byte) 0xb9, 0x17, 0x24, 0x42, (byte) 0xd7,  
		        (byte) 0xda, (byte) 0x8a, 0x06, 0x00, (byte) 0xa9, 0x6f, 0x30,  
		        (byte) 0xbc, (byte) 0x16, 0x31, 0x38, (byte) 0xaa, (byte) 0xe3,  
		        (byte) 0x8d, (byte) 0xee, 0x4d, (byte) 0xb0, (byte) 0xfb, 0x0e,  
		        0x4e };
国密SM4加解密--Java实现 【代码】国密SM4加解密--Java实现。 阅读详情

相关推荐

基于Java的SM4(ECB模式,CBC模式)对称加解密实现

加密算法依赖了groupId:org.bouncycastle中的bcprov-jdk,Bouncy Castle (bcprov-jdk15to18)提供了JDK 1.5 to 11 可使用的大量标准加密算法实现,其中包含了SM2,SM3,SM4。* @param key 密钥 (十六进制字符串: B6D8C12920418AFEA57514132E16039A)* @param content 待加密内容(普通字符串: 1234567812345678aa1100)

wjianwei666的专栏 6485

【转】Java实现国密算法SM2,SM3,SM4,并且实现ECB和CBC模式

代码中实现了电码本ECB模式和密文分组连接CBC模式,SM3.java和SM4.java为算法实现类,utils的都是根据实现类写的工具,可以根据需要调用杂凑算法SM3的杂凑功能获得杂凑值。 SM4.java中 sm4_crypt_ecb(SM4_Context ctx, byte[] input) ECB模式加解密方法,根据密钥判断加解密功能 sm4_crypt_cbc(SM4_Context ctx, byte[] iv, byte[] input) CBC模式加解密方...

4420

基于Java语言的国密SM2/SM3/SM4算法库 , 包含加密/解密、签名/验签、摘要计算的实现代码和测试方法 。

SM2_SM3_SM4Encrypt 项目介绍 最近有一个项目需要用到国密算法 , 具体是需要对接硬件加密机调用加密机的JAVA接口实现国密的一整套流程 , 但是由于公司测试环境和阿里云硬件加密机不通 , 所以只能自己模拟加密机的接口实现一套国密的软加密实现 。将有关国密的代码提取并分享出来 , 并且提供了详细的测试代码以供参考 。 项目中包括SM2算法的加密/解密/签名/验签 , SM3算法的摘要计算 , SM4算法的对称加密/解密 , 以及相应算法的公私钥对的生成方法。 项目测试脚本使用 在项目中的te

和我一起吧的博客 9734

Android国密算法实战:SM2、SM3、SM4在移动安全中的应用

本文详细介绍了在Android开发中集成国密算法(SM2、SM3、SM4)的完整实战方案。通过BouncyCastle库的配置、密钥生成与管理,结合具体代码示例,阐述了SM2非对称加密与签名、SM3消息摘要以及SM4对称加密在移动安全中的应用场景与最佳实践,帮助开发者构建自主可控、合规高效的数据安全防护体系。

weixin_29323551的博客 1201

Java实现SM4国密算法:ECB与CBC模式实战详解

对称加密是保障数据机密性的核心技术,其原理在于加密与解密使用同一密钥,确保信息传输的私密性。在分组密码中,算法将明文划分为固定长度的块进行处理,SM4作为我国商用密码标准,正是基于128位分组的对称加密算法,其技术价值在于满足金融、政务等领域的合规性要求。在实际工程实践中,开发者常需处理数据加密、安全传输等场景,并面临算法模式选择、填充机制等具体问题。本文聚焦于SM4算法的ECB与CBC两种核心模式,通过Bouncy Castle库的集成,提供了从密钥生成、加密解密到在线工具交叉验证的完整代码示例,并深入探

weixin_28607671的博客 309

国密算法SM2/SM3/SM4实战指南:从原理到Java实现(含ECB/CBC模式示例)

本文详细介绍了国密算法SM2、SM3和SM4的核心特性及Java实现,涵盖密钥生成、签名验签、数据完整性校验和密码存储等实战场景。通过对比分析ECB与CBC模式的优缺点,提供优化建议和安全实践,帮助开发者高效应用国密算法提升系统安全性。

weixin_29315569的博客 342

SpringBoot国密算法(SM2/SM3/SM4)详解:从入门到精通(含完整工具类)-全网最全

国密算法是由中国国家密码管理局制定的一系列密码算法标准,包括SM2(椭圆曲线公钥密码算法)、SM3(密码杂凑算法)和SM4(分组密码算法)等。这些算法是我国自主设计的商用密码算法体系,已广泛应用于金融、政务、通信等领域。 与传统的国际通用算法相比,国密算法具有以下优势: 1. 自主可控:完全由中国自主研发,避免了潜在的后门风险 2. 安全性高:采用更先进的密码学设计理念 3. 性能优越:在同等安全强度下,计算效率更高 4. 符合监管要求:满足我国网络安全法和密码法要求

本博客聚焦 YOLOv11 全流程落地,涵盖架构优化、数据集处理、训练技巧与多场景部署,兼及国产数据库、Java 开发与 AI 模型应用,内容兼顾理论与工程实践,为开发者提供系统干货,助力高效提升技术能力。 2453

Sourcetree与Gitee的搭配使用

初次将gitee与sourcetree联合起来使用,还是遇到了不少问题,其中最让人烦恼的就是在我修改了一下用户名之后,便无法在Sourcetree直接推送到gitee,很是让人郁闷。本文处理Sourcetree与gitee搭配使用过程中的问题:Sourcetree身份验证失败,无法推送;Sourcetree推送时,无法显示要推送的分支;Sourcetree远端上面有感叹号。

年少时的棉花糖 4433

浅谈车载控制器产线EOL实现方式

1、控制器生产产线上电路检测设计 2、客户总装产线检测设计

u012406840的博客 2万+

Isaacgym使用操作指南

Isaac Gym 是一个强大的仿真工具,特别适合那些需要进行大规模并行仿真和训练的机器人和强化学习任务。通过 GPU 加速、深度学习集成和丰富的物理仿真能力,Isaac Gym 能够显著提高仿真和训练效率,是机器人学和 AI 研究中的一大利器。

Tony Wey的博客 1万+

CST STUDIO SUITE 2023安装

破解工具的Crack文件夹内有一个名为「CST Studio Suite 2022」的文件夹,这也是于CST的安装目录同名的文件夹,直接把它拷贝到CST Studio Suite 2022的同级路径下即可,比如你的CST安装路径为:D:\Program Files\CST Studio Suite 2022,则将Crack目录内的「CST Studio Suite 2022」文件夹复制到 D:\Program Files\ 这个级别的路径下即可。软件百度网盘链接放在文章末尾啦!先不着急启动CST或者激活。

m0_49516223的博客 4116

[cshell]个性化配置你的cshrc/tcshrc

本文介绍了csh/tcsh shell的配置优化方法,主要包括:1. 配置文件管理(全局和个人配置);2. 按键绑定设置(解决远程登录按键问题);3. 提示符个性化(包含颜色配置方案);4. 环境变量设置(如LSCOLORS、CLICOLOR等);5. 安全防护措施(防误删、防覆盖等);6. 实用alias命令集(简化操作、提高效率)。文章提供了详细的配置示例,并建议通过man tcsh获取更多帮助信息。这些配置能显著提升shell使用体验和工作效率。

元直的博客 6110

FAA机载电子硬件审查指南详解(评审和审查必备)

本咨询通告旨在协助认证机构、授权代表(包括组织授权)和申请人执行机载电子硬件评审(以下简称"硬件评审")。硬件评审的目的是评估机载电子硬件是否符合适航要求和建议的符合性方法(即RTCA/DO-254)。本工作辅助文件应作为评审过程中的参考工具使用。它不应被用作检查表,也不包含所有可能需要评审的情况。同样,本工作辅助文件也不是用来替代DO-254,而应与DO-254一起使用。此外,本工作辅助文件可能包含一些不适用于特定项目评估的问题。

qq_41854911的博客 607

2024华为OD机试真题-矩阵匹配-C++-OD统一考试(C卷D卷)

​从一个 N * M(N ≤ M)的矩阵中选出 N 个数,任意两个数字不能在同一行或同一列,求选出来的 N 个数中第 K 大的数字的最小值是多少。输入描述输入矩阵要求:1 ≤ K ≤ N ≤ M ≤ 150

goldarmour的博客 279

小波变换完全指南:从原理到实践的深度解析

在信号处理领域,傅里叶变换长期以来一直是频域分析的主要工具。然而,傅里叶变换存在一个根本性的局限:它只能告诉我们信号中包含哪些频率成分,却无法告诉我们这些频率成分在什么时刻出现。这就像是你知道一首歌用了哪些音符,却不知道这些音符的演奏顺序。小波变换(Wavelet Transform) 应运而生,它完美地解决了这个问题。小波变换不仅能够提供频率信息,还能同时提供时间信息,实现了信号的时频联合分析。本文将带你从零开始,深入理解小波变换的原理、实现和应用。傅里叶变换的定义如下: 它使用正弦和余弦这样的全局基函数

电脑管家 207

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

上一篇: jvm 内存溢出,项目部署在tas服务器上,启项目时内存溢出报错问题排查。
下一篇: 解决maven打包报错,web项目依赖java项目的jar,使用server(如tomcat、tas等)可成功进行打包
Walter Sun
博客等级 码龄9年 1726粉丝 288原创
评论 15
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Walter Sun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值