几种图片加密方式及其原理

几种图片加密方式及其原理

1.图片隐写AES加密:

JPEG文件处理和加密数据的嵌入

JPEG格式是一种广泛使用的图像格式,支持高效的图像压缩。JPEG文件由多个部分组成,包括文件头、图像数据和可选的元数据段(如EXIF信息)。JPEG标准还允许在文件中添加自定义的注释段,这些段通常不会影响图像的显示。
加密后的数据可以被嵌入到JPEG图片中的几个不同位置,例如自定义的注释段或其他非图像数据部分。这样的嵌入方法利用了JPEG格式的灵活性,允许在不干扰图像本身的情况下存储额外信息。
当加密数据嵌入JPEG文件后,这些数据与图像内容本身分开存储,对图像的正常查看没有影响。JPEG图片看起来与未加密之前无异,因为加密数据被存储在图片的非视觉部分,如文件的元数据区域或注释段中。
加密数据的隐蔽性和安全性:

通过将加密数据嵌入JPEG文件,实现了一种隐蔽的加密方式。这种方法不仅保护了数据的安全性,还使得加密数据的存在不易被注意到。对于大多数用户来说,他们可能无法识别JPEG图片中包含加密数据,从而增加了数据保护的隐蔽性。
此外,即使有人注意到JPEG文件的大小或结构与普通JPEG图片有所不同,没有正确的密钥,他们也无法解密或理解嵌入的数据。这提供了一层额外的安全保障。

综上所述,通过将AES加密的数据嵌入到JPEG文件的非图像部分,这个过程不仅保证了数据的机密性和安全性,而且保持了图片的可视性和使用的灵活性。这种加密方法利用了JPEG格式的特性和AES算法的安全性,为敏感或私人数据的存储和传输提供了一个隐蔽且安全的解决方案。

加密步骤

  1. 参数和文件检查:检查输入的图片路径和输出路径,确认文件存在并且输出路径有效。

  2. 文件处理

    • 删除已经存在的加密文件,保证每次加密都是在干净的环境下进行。
    • 生成一个随机AES密钥,用于加密图片数据。
  3. 生成加密文件头

    • 创建一个文件头,包括随机AES密钥和可能的其他元数据(如原始文件长度和哈希值)。
    • 将加密文件头写入输出文件。
  4. AES加密图像数据

    • 使用AES密钥对原始图片文件进行加密。
    • 加密的数据被追加到包含文件头的输出文件中。
  5. 处理JPEG文件

    • 如果加密后的总长度小于预定义的最小JPEG文件长度,将填充数据添加到加密数据中,直到达到这个最小长度。
    • 选择一个目标JPEG文件,并将加密数据(包括文件头、加密图像数据和任何填充数据)嵌入到这个JPEG文件中,可能是通过添加到JPEG的评论段。
  6. 位置查找和数据插入

    • 在JPEG文件中找到适合插入加密数据的位置。
    • 将加密数据插入到JPEG文件的指定位置,这可能涉及到对JPEG文件进行修改,如添加或扩展评论段。
  7. 文件复制和清理

    • 将修改后的JPEG文件复制到最终的输出路径。
    • 删除临时文件和不再需要的加密数据文件。
  8. 错误处理:在整个过程中,如果遇到错误(如文件操作失败、加密错误等),将执行相应的错误处理逻辑,可能包括回滚操作、删除临时文件等。

伪代码:

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class JPEGSteganography {
    public static void main(String[] args) {
        try {
            // 1. 生成 AES 密钥
            SecretKey aesKey = generateAESKey();

            // 2. 要加密的数据
            byte[] dataToEncrypt = "Sensitive information".getBytes();

            // 3. 加密数据
            byte[] encryptedData = encryptData(dataToEncrypt, aesKey);

            // 4. 嵌入加密数据到 JPEG 文件
            File jpegFile = new File("input_image.jpg"); // 原 JPEG 文件路径
            embedDataIntoJPEG(jpegFile, encryptedData);

            System.out.println("加密数据已成功嵌入到 JPEG 文件中。");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static SecretKey generateAESKey() throws Exception {
        KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(256); // 可以使用 128, 192, 或 256 位密钥
        return keyGen.generateKey();
    }

    public static byte[] encryptData(byte[] data, SecretKey aesKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, aesKey);
        return cipher.doFinal(data);
    }

    public static void embedDataIntoJPEG(File jpegFile, byte[] encryptedData) throws IOException {
        // Step 1: 读取 JPEG 文件内容
        FileInputStream fis = new FileInputStream(jpegFile);
        byte[] jpegContent = new byte[(int) jpegFile.length()];
        fis.read(jpegContent);
        fis.close();

        // Step 2: 创建 JPEG 注释段
        byte[] commentSegment = createCommentSegment(encryptedData);

        // Step 3: 将注释段嵌入 JPEG 内容
        byte[] modifiedJPEG = new byte[jpegContent.length + commentSegment.length];
        System.arraycopy(jpegContent, 0, modifiedJPEG, 0, jpegContent.length);
        System.arraycopy(commentSegment, 0, modifiedJPEG, jpegContent.length, commentSegment.length);

        // Step 4: 保存修改后的 JPEG 文件
        FileOutputStream fos = new FileOutputStream("modified_" + jpegFile.getName());
        fos.write(modifiedJPEG);
        fos.close();
    }

    public static byte[] createCommentSegment(byte[] encryptedData) {
        // 创建注释段格式:0xFF 0xFE + 数据长度 + 数据内容
        int length = encryptedData.length + 2; // 长度包含头部
        byte[] commentSegment = new byte[length + 2];
        commentSegment[0] = (byte) 0xFF;
        commentSegment[1] = (byte) 0xFE; // 注释段标识
        commentSegment[2] = (byte) ((length >> 8) & 0xFF); // 高字节
        commentSegment[3] = (byte) (length & 0xFF); // 低字节

        System.arraycopy(encryptedData, 0, commentSegment, 4, encryptedData.length);
        return commentSegment;
    }
}

2.RSA+AES加密

加密步骤

  1. 生成 RSA 密钥对
在这里插入代码片
import java.security.KeyPair;
import java.security.KeyPairGenerator;

public class RSAUtils {
    public static KeyPair generateKeyPair() throws Exception {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(2048);
        return keyGen.generateKeyPair();
    }
}

  1. 生成 AES 密钥
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;

public class AESUtils {
    public static SecretKey generateAESKey() throws Exception {
        KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(256);
        return keyGen.generateKey();
    }
}

  1. AES 加密数据
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;

public class AESUtils {
    public static byte[] encryptData(byte[] data, SecretKey aesKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        byte[] iv = new byte[cipher.getBlockSize()];
        new SecureRandom().nextBytes(iv);
        IvParameterSpec ivParams = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE, aesKey, ivParams);
        byte[] encrypted = cipher.doFinal(data);
        return concatenateArrays(iv, encrypted);
    }

    private static byte[] concatenateArrays(byte[] a, byte[] b) {
        byte[] result = new byte[a.length + b.length];
        System.arraycopy(a, 0, result, 0, a.length);
        System.arraycopy(b, 0, result, a.length, b.length);
        return result;
    }
}

  1. 使用 RSA 加密 AES 密钥
import javax.crypto.Cipher;

public class RSAUtils {
    public static byte[] encryptAESKey(SecretKey aesKey, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(aesKey.getEncoded());
    }
}

  1. 使用 RSA 加密 AES 密钥
public class EncryptionProcess {
    public static void main(String[] args) throws Exception {
        // 生成 RSA 密钥对
        KeyPair keyPair = RSAUtils.generateKeyPair();
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();

        // 生成 AES 密钥
        SecretKey aesKey = AESUtils.generateAESKey();

        // 明文数据
        byte[] plaintextData = "Sensitive Information".getBytes();

        // 使用 AES 加密数据
        byte[] encryptedData = AESUtils.encryptData(plaintextData, aesKey);

        // 使用 RSA 加密 AES 密钥
        byte[] encryptedAESKey = RSAUtils.encryptAESKey(aesKey, publicKey);

        // 发送 encryptedData 和 encryptedAESKey
        // 此处可使用 HTTP POST 或其他方式发送加密数据和 AES 密钥
    }
}

伪造文件头

加密后的图片无法打开,我们通过添加文件头来让文件看起来像个正常图片文件。伪造文件头涉及到修改文件的前几个字节,以便图像查看器能够识别和打开该文件。
步骤概述
选择图像格式:确定您想要伪造的图像格式(如 JPEG、PNG 等)。
获取原始文件头:找到一个有效的图像文件的文件头(例如,JPEG 文件头为 FF D8 FF,PNG 文件头为 89 50 4E 47)。
加密图像数据:将原始图像进行加密。
创建伪造文件:将伪造的文件头和加密后的图像数据组合在一起,生成伪造的图像文件。
**伪代码示例 **
以下是伪代码示例,用于伪造 JPEG 图像文件头和合并加密后的数据:

function createFakeImageFile(encryptedData) {
    // Step 1: 定义 JPEG 文件头
    byte[] jpegHeader = new byte[] { (byte) 0xFF, (byte) 0xD8, (byte) 0xFF, (byte) 0xE0 };

    // Step 2: 创建输出文件
    File outputFile = new File("fake_image.jpg");
    FileOutputStream fos = new FileOutputStream(outputFile);

    // Step 3: 写入伪造的 JPEG 文件头
    fos.write(jpegHeader);

    // Step 4: 写入加密后的图像数据
    fos.write(encryptedData);

    // Step 5: 关闭文件输出流
    fos.close();
}

扩展:对视频文件的加密

可以用aes+rsa对视频文件进行加密,我们可以添加文件头让系统将加密后的文件识别为视频文件。

  1. 理解 MP4 文件格式
    MP4 文件由多个不同的盒子(Box)组成,每个盒子都有其特定的结构。MP4 文件的起始部分通常包含以下几个重要的文件头盒子:

ftyp: 文件类型盒子,指示文件格式
moov: 媒体数据描述盒子
mdat: 媒体数据盒子,包含实际的音视频数据
2. 获取有效的 MP4 文件头
可以从有效的 MP4 文件中提取文件头。例如,以下是一个简单的 MP4 文件头的结构示例:

00000000 00 00 00 20 66 74 79 70 69 73 6f 6d 00 00 00 00 |…ftypisom…|
00000010 00 00 00 1C 6D 6F 6F 76 00 00 00 00 00 00 00 00 |…moov…|

  1. 伪造 MP4 文件头的步骤
    伪代码示例:
function createFakeMP4File(encryptedData) {
    // Step 1: 定义 MP4 文件头 (ftyp + moov)
    byte[] mp4Header = new byte[] {
        0x00, 0x00, 0x00, 0x20, // ftyp size
        0x66, 0x74, 0x79, 0x70, // ftyp
        0x69, 0x73, 0x6f, 0x6D, // isom
        0x00, 0x00, 0x00, 0x00, // version + flags
        0x00, 0x00, 0x00, 0x1C, // moov size
        0x6D, 0x6F, 0x6F, 0x76  // moov
        // 这里可以添加更多有效的 MP4 文件头数据
    };

    // Step 2: 创建输出文件
    File outputFile = new File("fake_video.mp4");
    FileOutputStream fos = new FileOutputStream(outputFile);

    // Step 3: 写入伪造的 MP4 文件头
    fos.write(mp4Header);

    // Step 4: 写入加密后的视频数据
    fos.write(encryptedData);

    // Step 5: 关闭文件输出流
    fos.close();
}

3.图片猫脸变换

广义Arnold变换是一种针对非方形图像的图像置乱技术,它扩展了传统Arnold变换的应用范围,使其能够处理非正方形的图像。这种方法通过对非方形图像进行智能分割,将图像分成多个接近正方形的小区块,然后对每个小区块独立进行Arnold变换。此技术考虑到非方形图像在长宽比上的差异,通过分段处理确保变换能够均匀地覆盖到图像的每一个部分,包括任何可能的长边剩余部分。

具体实现中,首先判断图像是否为正方形:如果是,直接进行标准的Arnold变换;如果不是,则根据图像的长宽比确定分割的小区块尺寸。分割后,计算每个区块的偏移量,并对每个区块单独应用Arnold变换。这一过程可能会根据需要重复多次,以确保变换的效果。如果在图像的长边上存在剩余部分未被完全覆盖,该方法也会对这些剩余部分进行特别处理,确保整个图像都经过了均匀的变换处理。

该方法的优点在于,它允许非方形图像通过分割成多个小的正方形或接近正方形的区块来利用Arnold变换的优势,从而实现对图像的有效加密和混淆。这种策略不仅提高了Arnold变换在非方形图像上的适用性和效果,还保持了变换的核心目的——增加图像的隐蔽性和复杂度,使其在图像加密、数字水印和其他需要图像处理的应用领域中具有广泛的应用前景。

广义Arnold变换是一种在数字图像加密领域常用的技术,旨在通过对图像像素位置进行数学上的置乱操作,以保护图像内容的安全性。该变换依赖于两个关键参数,通常表示为(a)和(b),这些参数直接影响像素位置的置乱模式。变换过程涉及将每个像素的坐标((x, y))按照特定的数学公式重新计算,以确定像素在加密图像中的新位置((x’, y’))。

具体来说,广义Arnold变换通过以下公式确定像素的新位置:

[x’ = (ax + by) \mod N]
[y’ = (cx + dy) \mod N]

其中,(N)代表图像的尺寸,而(a, b, c, d)是变换的参数。取模运算(\mod)确保新计算出的像素位置位于图像的有效范围内。

这种置乱过程的一个关键特性是其可逆性。也就是说,通过应用逆向的Arnold变换,可以从加密图像中恢复出原始图像的像素排列。这种特性确保了加密图像可以被有效地解密,前提是解密者知道正确的变换参数和次数。

在图像加密的上下文中,广义Arnold变换的作用是将原始图像的像素位置打乱,以至于在没有解密密钥的情况下,任何人观看图像都无法辨认出原始内容。这种方法不仅增强了图像的安全性,也为确保敏感信息不被未经授权的用户访问提供了一层重要的保护。

详细化加密流程步骤

  1. 输入验证与图像解码

    • 验证输入图像路径和输出路径的有效性,确保路径存在且输出文件不存在,避免覆盖已有文件。不合法或存在问题时,返回相应错误代码。
    • 使用BitmapUtil.decodeFile方法解码图像文件,将其转换为位图对象,为后续加密处理做好准备。
  2. 像素数组转换

    • 利用BitmapUtil.bitmap2Array方法,将位图对象转换为像素数组。每个元素代表图像中一个像素点,便于后续的空间置乱处理。
  3. 空间置乱处理(包括Arnold变换)

    • 对像素数组执行空间置乱处理,通过一系列算法改变像素的空间分布,包括简单的像素交换和基于复杂数学函数的变换。
    • 使用Arnold变换方法,进行广义猫脸变换。这是一种特定的空间置乱技术,适用于改变像素点的空间位置,进而加密图像。
  4. 输出加密图像

    • 将加密和包装处理后的图像数据写入指定的输出路径,完成加密流程。

根据加密流程的描述和所提供的代码,解密步骤需要逆向执行加密过程中的操作。这包括Arnold变换的逆变换以及其他可能应用的像素置乱和转换方法的反向操作。以下是一个基于加密流程的解密步骤概述:

  1. 输入验证与图像解码
  • 验证输入加密图像路径的有效性,确保路径存在。不合法或存在问题时,返回相应错误代码。
  • 使用适当的方法解码加密图像文件,将其转换为位图对象,为后续解密处理做好准备。
  1. 像素数组转换
  • 利用适当的方法,将位图对象转换为像素数组。这一步骤与加密流程中的像素数组转换相同,目的是获得方便进行数学运算的像素数据格式。
  1. 空间置乱处理的逆向操作
  • 对于应用的空间置乱处理,包括Arnold变换,在解密过程中需要执行相反的操作来恢复原始图像。这可能包括执行与加密过程中相同数量的逆Arnold变换迭代,以便将像素恢复到它们的原始位置。
    • Arnold变换是可逆的,因此通过执行足够次数的逆变换(逆操作),可以恢复原始图像。通常,这意味着对于每次加密中执行的Arnold变换,解密时也需要执行相同次数的逆Arnold变换。
  1. 像素数组到位图的转换
  • 将经过逆向空间置乱处理的像素数组转换回位图格式。这一步骤是加密过程中像素数组转换步骤的直接逆操作,目的是从修改后的像素数据中恢复出可视的图像。
  1. 输出解密图像
  • 将解密后的位图数据保存到指定的输出路径,完成解密流程。这一步骤确保用户可以访问和查看已解密的原始图像。

需要注意的是,解密过程的准确性和成功与加密过程中使用的确切参数(如Arnold变换的参数a、b和迭代次数)密切相关。因此,在解密时,必须使用与加密相同的参数值来确保图像能够正确恢复。

4.语音频谱置乱

这种加密方法的核心原理在于转换和打乱音频PCM(脉冲编码调制)数据,以保护语音通信的安全。该过程利用频率域和时间域的操作,利用傅里叶变换改变音频信号的频谱属性。具体来说,它通过在频率域对信号进行分组和重新排序,以及在时间域对帧进行置乱和重组,来对原始音频数据进行加密。这样不仅改变了音频数据的表现形式,还增加了无授权监听者解密和理解音频内容的难度。

加密原理主要基于傅里叶变换(FFT)和置乱算法。傅里叶变换是将音频信号从时域转换到频域,这使得音频数据的频率成分可以被分析和处理。在频域置乱阶段,通过对频率分量进行重新排序,改变了原始音频信号的频率分布,这种处理对音频的听感影响较小,但能有效提高加密强度。随后,进行时域置乱,即通过改变音频帧的顺序来进一步加密数据。时域置乱通过分组和重排这些组中的帧,打乱了原始音频信号在时间上的连续性。这两种置乱方法的结合,实现了对音频数据的有效加密,增加了音频数据被非授权解密的难度。

加密流程详解

  1. 采样和分帧

    • 每次处理一个固定大小(1920字节)的数据块,这些数据块构成采样数组。随后,采样得到的数据根据预设的大小进行分帧处理。
  2. 频域置乱

    • 每个采样数组通过快速傅里叶变换(FFT)转换到频域,生成频谱数组。在频谱数组中,特别关注(20Hz,2kHz)(2kHz, 4kHz)这两个关键频率区间。对这些区间内的频率成分执行平移和交换操作,并根据固定的秘钥数组进行加权处理。这一步骤生成了复杂的置乱数组,显著改变了原始信号的频率分布,达到了频域混淆的目的。这种重新排序改变了音频信号的频谱结构,但不改变音频内容的本质。
  3. 逆变换

    • 经过精心设计的频域置乱处理后,数据通过逆FFT转换回时间域。逆变换保留了数据的时间序列结构,为接下来的时域置乱作准备。
  4. 时域置乱

    • 逆变换后的数据进一步经过时域置乱处理。根据密钥(timeEnKey)将音频帧分组,并在每个组内进行置乱。对于每个组内的音频帧,根据预设的密钥顺序进行重排,实现对音频数据时域上的置乱
      .时域置乱增加了数据的不可预测性,进一步加强了加密的安全性。
  5. 合帧输出加密数据

    • 输出前通过合帧处理重新组合成完整的PCM数据流。考虑帧与帧之间的重叠和窗函数应用,确保加密音频的连贯性和质量。输出的加密音频数据替代原始PCM数据流,保障音频内容的保密性和完整性。

解密流程

解密过程是加密操作的逆向执行,确保只有授权的接收者能够准确地恢复音频内容:

  • 时域反置乱:加密数据首先经过时域反置乱处理,恢复至置乱前的时间序列排列。
  • FFT变换:接着,数据被转换到频域,准备进行频域反置乱。
  • 频域反置乱:利用相同的密钥对频域数据进行精确的反置乱操作,尤其是针对(20Hz,2kHz)(2kHz, 4kHz)区间的特定处理,恢复原始的频率分布。
  • 逆FFT变换:最后,数据通过逆FFT变换回时间域,得到解密后的音频信号。
  • 输出解密数据:完成解密过程后,得到的时间域数据流便是原始的、未加密的音频信号,保证了数据的真实性和完整性。

通过在关键的频率区间进行精细的置乱和根据固定秘钥数组加权处理,这一加密方法不仅增强了音频数据的安全性,也保证了音频内容在授权的情况下能够被准确恢复。

前端加密有以下几种方式: 1. 对称加密:使用相同的密钥进行加密和解密,常见的算法有DES、3DES、AES等。实现方式如下: ```javascript // 加密 function encryptByAES(message, secretKey) { const key = CryptoJS.enc.Utf8.parse(secretKey); const encrypted = CryptoJS.AES.encrypt(message, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 }); return encrypted.toString(); } // 解密 function decryptByAES(ciphertext, secretKey) { const key = CryptoJS.enc.Utf8.parse(secretKey); const decrypted = CryptoJS.AES.decrypt(ciphertext, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 }); return decrypted.toString(CryptoJS.enc.Utf8); } ``` 2. 非对称加密:使用公钥和私钥进行加密和解密,常见的算法有RSA、DSA等。实现方式如下: ```javascript // 生成公钥和私钥 const keyPair = window.crypto.subtle.generateKey( { name: "RSA-OAEP", modulusLength: 2048, publicExponent: new Uint8Array([1, 0, 1]), // 65537 hash: "SHA-256" }, true, ["encrypt", "decrypt"] ); // 加密 async function encryptByRSA(message, publicKey) { const encodedMessage = new TextEncoder().encode(message); const encrypted = await window.crypto.subtle.encrypt( { name: "RSA-OAEP" }, publicKey, encodedMessage ); return window.btoa(String.fromCharCode(...new Uint8Array(encrypted))); } // 解密 async function decryptByRSA(ciphertext, privateKey) { const decodedCiphertext = Uint8Array.from( atob(ciphertext), c => c.charCodeAt(0) ); const decrypted = await window.crypto.subtle.decrypt( { name: "RSA-OAEP" }, privateKey, decodedCiphertext ); return new TextDecoder().decode(decrypted); } ``` 3. 散列加密:将数据转化为固定长度的散列值,常见的算法有MD5、SHA-1、SHA-256等。实现方式如下: ```javascript // 计算MD5散列值 function hashByMD5(message) { return CryptoJS.MD5(message).toString(); } // 计算SHA-256散列值 function hashBySHA256(message) { return CryptoJS.SHA256(message).toString(); } ``` 4. 混淆加密:通过混淆代码或者加入噪音的方式来增强安全性,常见的方式有代码混淆、字符替换等。实现方式如下: ```javascript // 字符串替换 function replaceChars(str) { return str.replace(/a/g, "@").replace(/e/g, "3").replace(/i/g, "1"); } // 代码混淆 function obfuscateCode(code) { // 实现方式可以使用自己的加密算法,这里只是示例 return code.split("").reverse().join(""); } ``` 需要注意的是,以上示例代码只是参考实现,实际情况需要根据具体需求进行修改和完善。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值