哈希算法霸权:从碰撞抗性到雪崩效应的算法统治

哈希算法霸权:从碰撞抗性到雪崩效应的算法统治

免责声明:用户因使用公众号内容而产生的任何行为和后果,由用户自行承担责任。本公众号不承担因用户误解、不当使用等导致的法律责任


目录

 

一:哈希算法介绍

1.哈希算法定义

2.哈希算法特性

3.哈希算法分类

二:哈希算法原理(MD5)

1.设置初始值

2.填充

3.分组

4.循环处理

5.累加

6.拼接

三:python实现哈希算法

1.文件哈希值

2.字符哈希值

3.sha1_crypto.py

4.sha1_hashlib.py

四:哈希算法应用场景

1. 数字签名

2. 文件防篡改

3. 重复文件检测

4. URL缩短与反爬虫

5. 数据库密码存储

五:哈希算法攻击方式及其安全性

1.MD5破解之法

2.其他破解方式

3.彩虹表

六:总结


一:哈希算法介绍

1.哈希算法定义

哈希算法是一种单向函数,能将任意长度的输入数据(如文本、文件、二进制流)转换为固定长度的唯一字符串(称为哈希值、散列值或摘要)。例如:

  • 128bit 哈希值:以十六进制表示时,每个字符占4位,共32位(如 e4d909c290d0fb1ca068ffaddf22cbd0)。

核心特性

  1. 无需密钥
    哈希计算不依赖密钥,仅基于输入数据本身生成结果(区别于需要密钥的加密算法或MAC)。
  2. 单向性(不可逆)
    无法通过哈希值逆向推导出原始输入数据(即使已知算法)。
  3. 确定性
    相同输入必然生成相同的哈希值。
  4. 输出长度固定
    无论输入数据大小,输出长度固定(如MD5为32位,SHA-3可自定义长度)。
  5. 抗碰撞性
    极难找到两个不同的输入产生相同的哈希值(强抗碰撞性)。
  6. 雪崩效应
    输入数据的微小变化(如1比特)会导致哈希值完全不同。

别名与关联概念

  • 散列算法、杂凑算法:中文对“Hash Algorithm”的直译,强调数据被打散混合的特性。
  • 摘要算法:强调哈希值是对数据的“摘要”或“指纹”,可唯一标识原始数据。
  • 与加密算法的区别
    • 哈希算法:单向,生成摘要,无密钥,用于验证完整性。
    • 加密算法(如AES、RSA):双向,需密钥,用于保护数据机密性。

2.哈希算法特性

特性说明示例或数学表达
确定性相同输入必定生成相同的哈希值。H("hello") ≡ 2cf24dba...(SHA-256)
敏感性(雪崩效应)输入数据的微小变化(如1比特)会导致哈希值完全不同。修改 hello → hallo → 7838a484...(SHA-256)
快速性无论输入数据大小,均能快速计算出哈希值。计算速度:SHA-256 ≈ 200MB/s(现代CPU)
单向性无法从哈希值逆向推导出原始输入数据。已知 H(x),无法解出 x(除非暴力破解)
强抗碰撞性极难找到两个不同输入产生相同的哈希值,碰撞概率极低(哈希空间为 2^nn为哈希长度)。

碰撞概率 ≈ 1/(2^n)(如MD5的 n=128

  • 输出长度:哈希空间结果数为 2^nn为位数),如:
    • MD5:n=128 → 结果空间 2^128(约3.4×10^38种可能)
    • SHA-256:n=256 → 结果空间 2^256(约1.1×10^77种可能)
  • 碰撞概率:根据生日攻击原理,找到碰撞的预期复杂度约为 √(2^n)

3.哈希算法分类

分类全称代表算法输出长度安全性典型应用场景
CRC循环冗余校验(Cyclic Redundancy Check)CRC-3232位非加密网络传输错误检测、存储校验
MD消息摘要算法(Message Digest)MD5128位不安全旧版文件校验(已淘汰)
SHA安全哈希算法(Secure Hash Algorithm)

SHA-1

160位不安全旧版数字签名(已淘汰)
SHA安全哈希算法(Secure Hash Algorithm)SHA-256256位安全比特币、SSL证书、密码存储
SHA安全哈希算法(Secure Hash Algorithm)SHA-512512位安全高安全性需求场景(如军事)
  1. CRC系列
    • 用途:专为错误检测设计(如文件传输、存储校验),不提供安全性
    • 示例:CRC-32广泛用于ZIP压缩包、以太网帧校验。
  2. MD系列
    • 特点:早期设计的哈希算法,MD5因碰撞漏洞(如“不同文件生成相同哈希值”)已淘汰。
    • 替代方案:使用SHA-2或SHA-3系列。
  3. SHA系列
    • SHA-1:2005年被证实存在碰撞攻击,不再安全
    • SHA-2(包括SHA-256、SHA-512):当前主流标准,抗碰撞性强,适用于高安全场景。
    • SHA-3:新一代算法(Keccak),设计更灵活,抗量子计算攻击。

二:哈希算法原理(MD5)

1.设置初始值

每32位一组共四组128位(A,B,C,D。四个寄存器

A = 0x67452301  
B = 0xEFCDAB89  
C = 0x98BADCFE  
D = 0x10325476

2.填充

N(长度)≡448(mod512) 如果不满足进行填充。前448位:放原始数据+填充的1(标记填充开始位置)和0,后64位:记录原始数据长度

总长度 = 原始长度 + 填充的1和0 + 64位长度记录

举个栗子

假设原始数据是 1000字节(8000位),填充步骤如下:


步骤1:填充1个1和若干个0

  1. 先加1个1:变成8001位。
    (添加标志位)
  2. 0直到长度 ≡ 448 mod 512
    • 计算 8001 ÷ 512 = 15 余 321 → 余数321 < 448,需要补到448。
    • 需要补的0的位数 = 448 - 321 -1 = 126位(因为已经加了1位1)。
    • 填充后总长度 = 8001 + 126 = 8127位(此时 8127 ≡ 448 mod 512)。

步骤2:附加64位的原始长度

  • 将这64位附加到填充后的数据末尾,总长度变为:8127 + 64 = 8192位 = 512 × 16(刚好是512的整数倍)。
  • N=16  也就是16个块

3.分组

(1) 填充后的数据总长度

  • 填充后的数据满足:总长度 = 512 × NN为整数)。
    例如:填充后数据为8192位 → 8192 ÷ 512 = 16块。

(2) 切割成512位块

  • 将数据按顺序切割为连续的512位块
    例如:8192位 → 块1(0-511位)、块2(512-1023位)… 块16(7680-8191位)。

(3) 每个块细分为16个32位子块

  • 子块划分:每个512位块被均分为16个32位(4字节)的子块,记为 M0,M1,…,M15
    例如:块1的512位 → 子块0(0-31位)、子块1(32-63位)… 子块15(480-511位)。

4.循环处理

四轮循环(每轮使用不同的非线性函数和位移数)

每轮需要16次操作四轮共需要64次操作

与(AND):用符号“∧”表示,表示同时满足两个命题的关系。

或(OR):用符号“∨”表示,表示两个命题中至少一个为真的关系。

非(NOT):用符号“¬”表示,表示否定或取反的关系。

异或(⊕):
同为 0,异为 1
轮次函数逻辑表达式行为特点
1F(B,C,D)(B ∧ C) ∨ (¬B ∧ D)根据B选择C或D
2G(B,C,D)(B ∧ D) ∨ (C ∧ ¬D)根据D选择B或C
3H(B,C,D)B ⊕ C ⊕ D三者的异或(奇偶校验)
4I(B,C,D)C ⊕ (B ∨ ¬D)复杂混合,打破对称性

每当一个块完成四轮循环后得到的A,B,C,D 和初始值A,B,C,D进行如下操作


5.累加

 

Ainitial​,Binitial​,Cinitial​,Dinitial​:处理当前块前的寄存器初始值



Acurrent​,Bcurrent​,Ccurrent​,Dcurrent​:四轮循环后的寄存器当前值。



Mod^26=当两个32位无符号整数相加的结果超过32位(即 ≥232≥232)时,超出部分的高位被丢弃,仅保留低32位。也叫溢出自动取模

然后将更新后的寄存器值 Anew,Bnew,Cnew,Dnew 作为下一个512位块的初始值,重复四轮循环操作


6.拼接

当所有512位块处理完毕后(也就是处理N次),最终的哈希值由最后一次更新的寄存器按小端字节序输出128位哈希值值拼接而成:

A = 0x5D41402A → 2A 40 41 5D  

B = 0xBC4B2A76 → 76 2A 4B BC  

C = 0xB9719D91 → 91 9D 71 B9  

D = 0x1017C592 → 92 C5 17 10  

拼接结果:5d41402abc4b2a76b9719d911017c592

三:python实现哈希算法

1.文件哈希值

利用python直接将文件读取为哈希值

当前代码路径下放置文本文件进行读取

也可以利用如下工具


代码如下

from hashlib import md5 from hashlib import sha1 from hashlib import sha256 from hashlib import sha512 class StreamHash(): """哈希摘要生成器""" def __init__(self, algorithm='md5', size=1024): self.size = size alg = algorithm.lower() if alg == 'md5': self.hash = md5() elif alg == 'sha1': self.hash = sha1() elif alg == 'sha256': self.hash = sha256() elif alg == 'sha512': self.hash = sha512() else: raise ValueError('不支持指定的摘要算法') # 魔法方法: 让对象可以像函数一样被调用 def __call__(self, stream): return self.to_digest(stream) def to_digest(self, stream): """生成十六进制形式的哈希摘要字符串""" for data in iter(lambda: stream.read(self.size), b''): self.hash.update(data) return self.hash.hexdigest() def main(): # hash = md5() sh = StreamHash() with open('1.txt', 'rb') as stream: # for buf in iter(lambda: stream.read(4096), b''): # hash.update(buf) # print(hash.hexdigest()) #print(sh(stream)) print(sh.to_digest(stream)) if __name__ == '__main__': main() ///file_hash.py

2.字符哈希值

crypto库实现哈希值

python生成的哈希值和网站md5值相同

# python 版本 3.x # windows安装依赖:pip install pycryptodome # Linux安装依赖: pip install pycrypto from Crypto.Hash import MD5 obj1 = MD5.new() obj1.update(b"123456") print(obj1.hexdigest()) obj2 = MD5.new() obj2.update("安全瞭望Sec".encode('utf-8')) print(obj2.hexdigest()) ///md5_crypto.py

hashlib库实现哈希值

import hashlib # 英文计算哈希值 m = hashlib.md5() m.update(b'123456') # 返回16进制字符串 print(m.hexdigest()) # 中文计算哈希值 data = '安全瞭望Sec' enc = data.encode(encoding='utf-8') value = hashlib.md5(enc).hexdigest() print(value) ///md5_hashlib.py

3.sha1_crypto.py

# python 版本 3.x # windows安装依赖:pip install pycryptodome # Linux安装依赖: pip install pycrypto from Crypto.Hash import SHA1 sha1 = SHA1.new() sha1.update("安全瞭望Sec".encode('utf-8')) # print(sha1.digest()) # 返回字节串 print(sha1.hexdigest()) # 返回16进制字符串

4.sha1_hashlib.py

与sha1_crypto.py代码结果相同

import hashlib string='安全瞭望Sec' sha1 = hashlib.sha1() sha1.update(string.encode('utf-8')) res = sha1.hexdigest() print(res)

四:哈希算法应用场景

1. 数字签名

  • 原理
    发送方用哈希算法(如SHA-256)对服务器公钥生成消息摘要,再用私钥加密摘要形成数字签名。接收方用公钥解密签名获取哈希值,并与重新计算的哈希对比,验证消息完整性和来源真实性。
  • 关键点
    • 必须选择抗碰撞的哈希算法(如SHA-2/3系列)。
    • 结合非对称加密(如RSA、ECC)实现身份认证。
  • 注意事项
    • 避免使用MD5、SHA-1等已被破解的算法。
    • 定期更新密钥对以应对潜在泄露风险。

2. 文件防篡改

  • 原理
    文件发布者计算文件的哈希值(如SHA-256校验和),用户下载后重新计算哈希并与官方值比对。若不一致,则文件可能被篡改。
  • 增强安全性
    • 结合数字签名:哈希值由发布者私钥签名,防止哈希值本身被篡改。
    • 使用HTTPS分发哈希值,避免中间人攻击。
  • 典型场景
    • 软件下载、固件更新、法律文档传输。

3. 重复文件检测

  • 原理
    通过哈希值(如MD5、SHA-1)唯一标识文件内容,相同哈希值的文件视为重复。
  • 优化策略
    • 分块哈希:对大文件分块计算哈希,提升效率(如BitTorrent)。
    • 二次验证:哈希匹配后,逐字节比对防止冲突。
  • 注意事项
    • 避免仅依赖短哈希(如MD5),选择长哈希(如SHA-256)减少碰撞概率。
    • 云存储中常用内容寻址存储(如IPFS),直接以哈希作为文件地址。

4. URL缩短与反爬虫

  • 应用场景
    • 短链生成:将长URL哈希后编码为短字符串(如Base62)。
    • 反爬虫:将自增ID通过哈希混淆,生成无规律字符串(如1→aX3f2→gT7y),阻止顺序遍历。
  • 实现步骤
    1. 对原始URL计算哈希(如MurmurHash)。
    2. 将哈希值转换为Base62等短字符串。
    3. 处理冲突:若短码已存在,追加随机字符或重试。
  • 注意事项
    • 选择高效哈希算法(如CRC32、MurmurHash)以支持高并发。
    • 结合数据库唯一索引解决冲突。

5. 数据库密码存储

  • 问题
    简单哈希(如MD5)易受彩虹表攻击,且相同密码哈希值相同。
  • 正确实践
    • 加盐(Salt):为每个密码生成随机盐值,与密码组合后再哈希。
    • 慢哈希函数:使用bcrypt、scrypt或Argon2,增加计算成本,抵御暴力破解。
  • 示例流程
    1. 用户注册时生成随机盐。
    2. 计算hash = bcrypt(password + salt)
    3. 存储hashsalt到数据库。
  • 注意事项
    • 盐值需足够长(≥16字节)且唯一。
    • 定期升级哈希算法参数(如迭代次数)。

五:哈希算法攻击方式及其安全性

1.MD5破解之法

碰撞攻击

  • 原理
    找到两个不同的输入 M1≠M2,使它们的MD5哈希值相同(即 MD5(M1)=MD5(M2))。
  • 实现方式
    • 数学构造法利用MD5算法的结构漏洞(如块处理、填充规则)构造碰撞
    • 工具辅助:使用开源工具(如 fastcollHashClash)自动生成碰撞文件。
  • 经典案例
    • 2004年:王小云团队首次公开MD5碰撞方法,理论复杂度从 264264 降至 240240。
    • 2008年:研究人员生成伪造的SSL证书,与合法证书具有相同的MD5值,导致信任链被破坏。
    • 2012年:生成两个不同内容的PDF文件但MD5相同,可绕过文件校验。

2.其他破解方式

1.攻击类型

攻击类型原理/描述工具/示例防御措施备注
暴力破解穷举所有可能的明文组合,生成MD5哈希进行匹配。Hashcat、John the Ripper
(如:hashcat -m 0 -a 3 <hash> ?a?a?a?a?a?a
1. 强制长密码(≥12位)
2. 使用慢哈希算法(如Argon2、bcrypt)
3. 限制登录尝试次数
GPU加速(如RTX 4090)可大幅缩短破解时间。
字典攻击使用预定义的常见密码库(如rockyou.txt)生成MD5哈希匹配。Hashcat、Hydra
(如:hashcat -m 0 -a 0 <hash> rockyou.txt
1. 禁用弱密码库中的密码
2. 密码复杂度策略(大小写+数字+符号)
3. 多因素认证(MFA)
约80%的密码泄露源于弱密码或重复使用。
查表法通过在线平台(cmd5.com、md5.cn、somd5.com)查询预存的明文-MD5映射。在线平台直接提交哈希(如:e10adc3949ba59abbe56e057f20f883e1234561. 强制加盐(随机盐值)
2. 弃用MD5,改用SHA-256或专用密码哈希算法(如bcrypt)
仅对未加盐的短密码或常见字符串有效。
彩虹表攻击利用预生成的哈希链(彩虹表)快速反推未加盐的MD5哈希。RainbowCrack、Ophcrack
(如生成7位小写字母彩虹表)
1. 唯一盐值(每个用户独立随机盐)
2. 使用密钥派生函数(如PBKDF2、Argon2)
7位小写字母彩虹表约需200GB存储,加盐可完全防御。

2.优缺点

攻击类型优点缺点
暴力破解1. 理论上可破解任何密码(覆盖全部可能性)
2. 工具成熟(如Hashcat支持GPU加速)
1. 对长密码或复杂密码效率极低(如12位混合字符需数百年)
2. 计算资源消耗大(需高性能硬件)
字典攻击1. 针对弱密码高效(秒级破解常见密码)
2. 依赖现成密码库(如rockyou.txt)
1. 无法破解复杂密码(若密码不在字典中)
2. 依赖字典质量(需持续更新弱密码库)
查表法1. 即时破解(直接查询在线平台)
2. 无需本地计算资源
1. 仅适用于未加盐的短密码或常见字符串
2. 无法破解随机长密码或加盐哈希
彩虹表攻击1. 预计算后破解速度快(分钟级)
2. 存储优化(链式结构减少空间占用)
1. 生成彩虹表耗时耗存储(如7位密码需200GB)
2. 加盐哈希完全免疫此类攻击

3.总结对比

攻击类型最佳适用场景最弱防御场景防御优先级
暴力破解短密码、弱策略系统(如6位数字)无盐,短密码存储强制长密码 + 慢哈希算法
字典攻击用户使用常见弱密码无密码复杂度策略的系统禁用弱密码 + 多因素认证
查表法未加盐的常见短密码使用MD5且未加盐的遗留系统加盐 + 升级哈希算法
彩虹表攻击未加盐的历史密码库早期未升级的数据库(如MD5明文存储)唯一盐值 + 密钥派生函数(如PBKDF2)

3.彩虹表

彩虹表的核心概念

  • 定义
    彩虹表是一种预计算的哈希链,用于快速破解未加盐的哈希密码。通过“哈希链”减少存储需求,提升破解效率。
  • 核心组件
    • 哈希函数(H):如MD5、SHA-1等。
    • 归约函数(R):将哈希值映射回可能的明文空间(例如:取哈希值前几位转换为字符)

彩虹表攻击图

具体攻击方式原理参考:深入浅出彩虹表原理-腾讯云开发者社区-腾讯云

彩虹表攻击时间

字符集字母字母 + 数字字母 + 数字 + 常用符号全部字符集
哈希链长度210024001200020000
哈希链个数80000004000000040000000100000000
表单数量571320
成功率99.9%99.9%99.9%99.3%
文件大小640MB4480MB8320MB32000MB
最大生成时间17 小时5 天 14 小时52 天332 天
最大破解时间7 秒14 秒11 分48 分

彩虹表的优缺点

优点缺点
1. 预计算后破解速度快(分钟级)1. 生成耗时(需数天至数周)
2. 存储优化(链式结构)2. 无法破解加盐哈希
3. 覆盖常见短密码3. 长密码或复杂字符集不适用
彩虹表下载地址:http://project-rainbowcrack.com/table.htm

六:总结

哈希算法通过不可逆计算将任意数据转换为固定长度的唯一摘要值,确保数据完整性、安全验证及身份认证,其安全性依赖抗碰撞能力,需选用如SHA-256等现代算法抵御攻击。

算法输出长度(位)安全性碰撞攻击典型应用场景现状与建议
CRC-3232无安全性,仅用于错误检测易构造碰撞(设计目标非抗碰撞)网络传输校验(如以太网帧)、文件完整性初检不用于安全场景,仅保留在非安全校验场景。
MD5128已破解(2004年王小云团队实现高效碰撞攻击)可在数秒内生成碰撞(如fastcoll工具)历史遗留系统、非安全文件校验(如下载临时校验)完全弃用安全场景,升级为SHA-256或SHA-3。
SHA-1160已破解(2017年Google的SHAttered攻击实现实际碰撞)理论成本约 263263,实际攻击可行旧版SSL证书、Git版本控制(已逐步淘汰)立即替换,使用SHA-256或SHA-3替代。
SHA-256256安全(目前无公开有效攻击)理论碰撞复杂度 21282128,实际不可行比特币、数字签名、TLS/SSL证书、密码存储(结合KDF)推荐使用,适用于大多数安全场景。
SHA-512512更安全(抗量子计算潜力优于SHA-256)理论碰撞复杂度 22562256,安全性更高高安全性需求场景(如军事加密、金融系统)推荐使用,适合对安全性和抗量子计算有更高要求的场景。

(需要源代码及各类资料联系博主免费领取!!还希望多多关注点赞支持,你的支持就是我的最大动力!!!)

Read more

ollama 模型管理、删除模型 、open-webui 开启大模型交互

ollama 模型管理、删除模型 、open-webui 开启大模型交互

文章目录 * ollama 基本信息 * ollama 运行模型 * ollama 模型管理 * 🔧 **方法一:使用命令行删除单个模型** * ⚙️ **方法二:批量删除所有模型** * 🗑️ **方法三:彻底卸载 Ollama(含所有数据)** * ⚠️ **注意事项** * ✅ **验证是否删除成功** * open-webui 安装 开启大模型交互 * open-webui pip 安装 * open-webui 启动服务 * 浏览器访问 http://IP:8082/ : * ❤️ 时不我待,一起学AI ollama 基本信息 * https://ollama.com/ ollama 运行模型 命令行执行即可 0.6B parameter model ollama run qwen3:0.6b 1.7B

By Ne0inhk
2026年,给大家普及一下字节前端岗需要达到的强度

2026年,给大家普及一下字节前端岗需要达到的强度

字节跳动前端开发工程师岗      一面 1. 平时负责或深入的技术栈与业务方向,核心用户场景与技术价值主张 2. 前端开发生命周期管理,从需求分析、UI/UX协作到开发测试、性能优化的全流程实践与质量保障 3. 技术选型调研与用户体验数据应用,如何验证框架/方案选择并定位体验瓶颈 4. 项目开发中如何实现高效跨职能协同(产品、设计、后端、测试),关键协作流程与工具链 5. 竞品或业界方案分析框架与技术差异化策略制定,关注性能体验、工程效率与可维护性 6. 用户交互路径分析与体验优化项目(如加载性能、交互动效、无障碍访问)的构建机制 7. 关键性能指标监控与项目质量评估体系(如LCP、FCP、CLS、错误率) 8. 现代前端开发与传统网页开发模式区别,业务在不同阶段(初创、增长、复杂化)的技术重点与架构演进 9. 案例分析:给定新业务场景(如互动玩法、复杂中后台)

By Ne0inhk
【征文计划】玩转 Rokid JSAR:基于 Web 技术栈的 AR 开发环境搭建、核心 API 应用与 3D 时钟等创意项目全流程解析

【征文计划】玩转 Rokid JSAR:基于 Web 技术栈的 AR 开发环境搭建、核心 API 应用与 3D 时钟等创意项目全流程解析

【征文计划】玩转 Rokid JSAR:基于 Web 技术栈的 AR 开发环境搭建、核心 API 应用与 3D 时钟等创意项目全流程解析 前言 随着 AR 技术在消费级场景的普及,开发者对 “低门槛、高兼容” AR 开发工具需求愈发迫切,传统 AR 开发往往依赖专属引擎或复杂语法,导致 Web 开发者难以快速切入,而 Rokid 推出的 JSAR 技术,恰好打破了这一壁垒:以 “可嵌入空间的 Web 运行时” 为核心,让开发者无需学习新的开发范式,仅用 JavaScript/TypeScript 等熟悉的 Web 技术栈,就能快速开发出支持 3D 物体、

By Ne0inhk
安利一款超实用的前端可视化打印设计器:Vue Print Designer

安利一款超实用的前端可视化打印设计器:Vue Print Designer

做前端开发的朋友应该都懂,业务开发中遇到打印需求真的头大 —— 手写分页逻辑繁琐、不同框架适配麻烦、票据 / 快递单这类定制化打印场景不好实现,找个趁手的打印插件更是难上加难。最近发现了一款开源的可视化打印设计器Vue Print Designer,完美解决了这些痛点,不管是快速开发还是企业级定制化需求都能满足,今天就跟大家详细聊聊这款工具。 一、Vue Print Designer 是什么? Vue Print Designer 是一款面向业务表单、标签、票据、快递单等打印场景的可视化设计器,核心主打模板化、变量化设计,还提供了静默打印、云打印能力,同时支持 PDF / 图片 / Blob 等多种导出方式,完全能覆盖日常开发中的各类打印需求。 它不是简单的打印插件,而是一套完整的打印解决方案,从可视化设计模板,到参数配置、多端打印,再到定制化扩展,一站式搞定,而且项目还在持续更新,最新版本已经支持英寸、厘米作为单位,对国际化和精细化设计更友好了。 项目地址:https://gitee.com/

By Ne0inhk