当前位置: 首页 > news >正文

浅谈RC4

一、什么叫RC4?优点和缺点

      RC4是对称密码(加密解密使用同一个密钥)算法中的流密码(一个字节一个字节的进行加密)加密算法。

  优点:简单、灵活、作用范围广,速度快

  缺点:安全性能较差,容易被爆破

   密钥长度可变

以一个足够大的表S为基础,对表进行非线性变换(一个变换就是一个函数),从而产生密钥流

 二、加密解密原理


      1.初始化S表(KSA):
   

对S表进行线性填充,s[0]=0到s[255]=255,一般为256个字节;

    用种子密钥填充另一个256字节的K表,如果种子密钥是256的话,那么刚好填充完K表,如果校园长度小于256的话,K表里面的值就密钥的循环使用;

    用K表对S表进行初始置换,就是从s[0]开始到s[255],对每个s[i]根据k[i]确定一个方案,将s[i]置换为s中的另一个字节;

假设种子密钥是3,4,5  那么进行循环填充

从i=0到 i=255都要进行表内置换,根据公式,j=0+0+3=3,而 mod 256,这里mod 7然后将s[0]和s[3]进行一个置换,那么就得到新的3,1,2,0,4,5,6,将将这个过程循环七次后得到最后的那个S表

  S表一但完成初始化,种子密钥就不再使用了

     

  2.生成密钥流(PRGA)

  因为是流密码,所以我们需要为每个待加密的字节生成一个用来异或的随机数值,这个数值也是从s表中获取,那么接下来就是找到它的下标

例如:代码

得到 i=1,j=0,t=3,t就是下标的值

3.密钥流与明文进行异或

三、Python和c语言实现简单的RC4

    c语言:

#include<stdio.h> 
#include<stdlib.h>
#include<string.h>//s表的长度取256
#define size 256unsigned char sbox[257]={0};//初始化s表
void init_sbox(unsigned char*key){unsigned int i,j,k;int tmp;for(i=0;i<size;i++){sbox[i]=i;}j=k=0;for(i=0;i<size;i++){tmp=sbox[i];j=(j+tmp+key[k])%size;sbox[i]=sbox[j];sbox[j]=tmp;if(++k>=strlen((char*)key))k=0;}
}//加解密函数
void enc_dec(unsigned char*key,unsigned char*data){int i,j,k,R,tmp;init_sbox(key);j=k=0;	for(i=0;i<strlen((char*)data);i++){j=(j+1)%size;k=(k+sbox[j])%size;tmp=sbox[j];sbox[j]=sbox[k];sbox[k]=tmp;R=sbox[(sbox[j]+sbox[k])%size];data[i]^=R;}	
}int main(){unsigned char key[100]={0};unsigned char data[100]={0};printf("输入你要加密的字符:");scanf("%100s",data);printf("输入密钥:");scanf("%40s",key);enc_dec(key,data);printf("enc: %s\n",data);enc_dec(key,data);printf("dec: %s\n",data);return 0;
}

pyhthon实现:

def ksa(key):S = list(range(256))j = 0for i in range(256):j = (j + S[i] + key[i % len(key)]) % 256S[i], S[j] = S[j], S[i]  # 交换 S[i] 和 S[j]return Sdef prga(S):i = 0j = 0while True:i = (i + 1) % 256j = (j + S[i]) % 256S[i], S[j] = S[j], S[i]  # 交换 S[i] 和 S[j]K = S[(S[i] + S[j]) % 256]yield Kdef rc4_encrypt(key, plaintext):S = ksa(key)prga_gen = prga(S)ciphertext = bytearray()for byte in plaintext:K = next(prga_gen)ciphertext.append(byte ^ K)return ciphertextdef rc4_decrypt(key, ciphertext):# 对于 RC4,加密和解密过程是相同的return rc4_encrypt(key, ciphertext)# 示例用法
key = b'Secret'
# 原始字符串
plaintext= "Hello, World!"# 将字符串转换为UTF-8编码的字节串
utf8_bytes = plaintext.encode('utf-8')ciphertext = rc4_encrypt(key, utf8_bytes)
print('Ciphertext:',utf8_bytes)
decrypted_text = rc4_decrypt(key, ciphertext)
print('Decrypted Text:', decrypted_text)

         
     

四、例题

RC4的密码较为简单,所以要一般结合其他的东西再来解

比如buuctf上的re

[GUET-CTF2019]encrypt

    下载后查壳,没有,直接用IDA打开

发现了一串奇怪的字符

按X 后T按ab键,查看伪代码

观察一下,大概意思就是读取用户输入一段字符串并验证是否与byte_602080相匹配,还有sub_4006B6进行了RC4加密 ,v10就是key

看了一下其他的内容:

这里看到了base64加密和RC4加密的过程,但是这里的base64加密有点不一样,

   编码后的Base64字符是通过加上61(即ASCII中的'='字符加1)得到的,通过简化而形成的,一般的base64,通过'A''Z''a''z''0''9''+''/',而这里使用了'='字符加偏移的方式。查询得到是魔化的base64

什么叫做魔化的base64?

魔化的Base64通常指的是Base64编码的一种变体或改进形式,它在标准Base64的基础上进行了某些修改或增强,以适应特定的应用场景或需求。特点:

  1. 字符集变更
    • 标准Base64使用64个字符的字符集,包括大小写字母、数字、加号(+)、斜杠(/)以及填充字符等号(=)。
    • 魔化Base64可能会更改这个字符集,以避免在特定上下文(如URL、数据库或编程环境)中的冲突或特殊解释。
  2. URL安全
    • 由于标准Base64中的加号(+)和斜杠(/)在URL中具有特殊含义,因此直接用于URL中可能会导致问题。
    • 魔化Base64可能会使用其他字符(如连字符(-)和下划线(_))来替换加号(+)和斜杠(/),从而使其URL安全。
  3. 填充字符
    • 标准Base64使用等号(=)作为填充字符,用于在原始数据长度不是3的倍数时进行填充。
    • 魔化Base64可能会保留这个特性,但也可能根据具体应用场景进行不同的处理。
  4. 数据长度和膨胀
    • Base64编码的特性之一是它会使数据变大,因为每3个字节的原始数据会转换为4个Base64字符。
    • 魔化Base64通常不会改变这个基本的数据膨胀率,但在某些情况下可能会进行优化或调整。
  5. 编码/解码过程
    • 魔化Base64的编码和解码过程与标准Base64类似,但会基于变更的字符集和可能的特殊规则进行调整。
  6. 应用场景
    • 魔化Base64常用于需要Base64编码但又有特殊需求的场景,如URL编码、数据库存储、编程环境等。

大神wp的补充:

  1. 把 rc4 加密过的内容三个字节一组,变成四个六位的数(这里和 base64 原理一样)
  2. 把四个数每个加上 61,存入输出的数组之中

后面就没有什么了,再次梳理一下内容:先用RC4加密——魔化的base64——最后对比

大神接下来就是上脚本了,直接一步得到flag:


 

from base64 import *
import binascii
from Crypto.Util.number import *
duibi="Z`TzzTrD|fQP[_VVL|yneURyUmFklVJgLasJroZpHRxIUlH\\vZE="
# for i in range(len(duibi)-1):
#     print(hex(ord(duibi[i])-61),end=",")#得到shuru
shuru=[0x1d,0x23,0x17,0x3d,0x3d,0x17,0x35,0x7,0x3f,0x29,0x14,0x13,0x1e,0x22,0x19,0x19,0xf,0x3f,0x3c,0x31,0x28,0x18,0x15,0x3c,0x18,0x30,0x9,0x2e,0x2f,0x19,0xd,0x2a,0xf,0x24,0x36,0xd,0x35,0x32,0x1d,0x33,0xb,0x15,0x3b,0xc,0x18,0x2f,0xb,0x1f,0x39,0x1d,0x8,0]
def four_to_three(a1,a2,a3,a4):return (a1<<18)|(a2<<12)|(a3<<6)|a4
for i in range(0,len(shuru),4):temp=four_to_three(shuru[i],shuru[i+1],shuru[i+2],shuru[i+3])a1=temp>>16a2=(temp>>8)&0xffa3=(temp)&0xffprint(hex(a1)[2:].rjust(2,'0'),end="")print(hex(a2)[2:].rjust(2,'0'), end="")print(hex(a3)[2:].rjust(2,'0'), end="")
data1="7635fdf57d47fe95137a26593fff31a1857c63026ebd936a3e4d8dd727732d5ecc62f2dfe5d2"
def rc4_crypt(text,key):textlen=len(text)keylen=len(key)ciper=[]count=0s=list(range(256))for i in range(256):count=(count+s[i]+key[i%keylen])%256s[i],s[count]=s[count],s[i]i=0j=0for m in range(textlen):i=(i+1)%256j=(j+s[i])%256s[i],s[j]=s[j],s[i]k=s[(s[i]+s[j])%256]ciper.append(k^text[m])ciper_text=''.join("%02x"%i for i in ciper)return ciper_text.upper()
if __name__ == "__main__":data = '7635fdf57d47fe95137a26593fff31a1857c63026ebd936a3e4d8dd727732d5ecc62f2dfe5d2'key = '1020303020201040'print()print("rc4 result:", rc4_crypt(binascii.a2b_hex(data), binascii.a2b_hex(key.upper())))print(long_to_bytes(0x666C61677B65313061646333393439626135396162626535366530353766323066383833657D))#7635fdf57d47fe95137a26593fff31a1857c63026ebd936a3e4d8dd727732d5ecc62f2dfe5d200
#rc4 result: 666C61677B65313061646333393439626135396162626535366530353766323066383833657D
#b'flag{e10adc3949ba59abbe56e057f20f883e}'

那我们的一般思路就是将一开始的奇怪字符串进行Rc4解密,

如果借助在线网站的话,要将key进行十六进制转化,然后再弄,但是得到了的是魔化的base64,不行,

接下来就是利用特性:

RC4加密算法最后是要得到一个数据和明文进行异或

*(_BYTE *)(i + a2) ^= LOBYTE(v9[(unsigned __int8)(v7 + v8)]);

该数据 xor 明文=密文

密文 xor 该数据 =明文

那么要进行动态调试,在liucx里面弄

那么先下载IDA Pro

先去该网站下载

然后赋给执行权限并安装

chmod +x idafree83_linux.run

详解在:[GUET-CTF2019]encrypt_[guet-ctf2019]encrypt详细解答-CSDN博客

[GUET-CTF2019]encrypt 题解-阿里云开发者社区

[SEETF 2023]BabyRC4

题目:

分析过程:
     ARC4 :这一行导入一个叫ARc4的加密算法,ARC4就是RC4

   urandom:生成随机字符串

flag = b'SEE{?????????????????????????????????}'[::-1]: 定义了一个字节字符串,其内容为'SEE{'后面跟着32个问号,进行了字符串反转了。但反转后,其内容仍然是'SEE{'开头,后跟32个问号,只是问号的顺序与原始顺序相反。

print(f"c0 = bytes.fromhex('{enc(flag).hex()}')"): 使用定义的加密函数enc加密flag,将加密后的字节转换为十六进制字符串,并再次将其转换回字节。不能直接以字节的形式输出,因为先将字节转为16进制,再次转为字节可以检查转换后的字节是否与原始字节相同,确保数据的完整性,而且16进制利于传输和储存

print(f"c1 = bytes.fromhex('{enc(b'a'*36).hex()}')") :加密了一个由36个'a'字符组成的字节字符串,并进行了类似的转换。

那么按我们的思路来编写脚本吧!!!

     引入解决RC4的Python函数,这里使用的是strxor,是pycryptodome库中的一个实用函数,用于对两个等长的字节字符串执行按位异或(XOR)操作。异或操作是一种二进制运算,其结果中每一位是相应位置的两个输入位中恰有一个为1时取1,RC4过程中就要进行明文和数据的异或。

      定义m1,c0,c1

m1 是一个由36个'a'字符组成的字节串,每个'a'在ASCII中对应的字节值是0x61

c0c1 是从十六进制字符串转换而来的字节串,分别代表两个加密或编码后的数据块

最后就可以进行异或,

 strxor(m1,c1)m1c1进行异或操作。由于m1c1都是36字节长,所以它们的异或结果也是一个36字节长的字节串。

  c0[:-2]接着,我们从c0中移除最后两个字节(为了匹配m1c1的长度)。现在是一个34字节长的字节串。

  strxor(c0[:-2],...)c0[:-2]m1c1的异或结果进行异或操作。由于c0[:-2]只有34字节,而m1c1的异或结果是36字节逻辑上是不正确的,因为按位异或要求两个操作数具有相同的长度。但是,在Python中,较短的字节串会在其末尾用\x00(零字节)填充到与较长字节串相同的长度,然后再执行异或操作

最后就写成了解题脚本:

from Crypto.Util.strxor import strxorm1 = b'a'*36
c0 = bytes.fromhex('b99665ef4329b168cc1d672dd51081b719e640286e1b0fb124403cb59ddb3cc74bda4fd85dfc')
c1 = bytes.fromhex('a5c237b6102db668ce467579c702d5af4bec7e7d4c0831e3707438a6a3c818d019d555fc')flag = strxor(c0[:-2],strxor(m1,c1))
flag = b"SE"+flag[::-1]
print(flag)


 

相关文章:

浅谈RC4

一、什么叫RC4&#xff1f;优点和缺点 RC4是对称密码&#xff08;加密解密使用同一个密钥&#xff09;算法中的流密码&#xff08;一个字节一个字节的进行加密&#xff09;加密算法。 优点&#xff1a;简单、灵活、作用范围广&#xff0c;速度快 缺点&#xff1a;安全性能较差&…...

uniapp微信小程序开发物料

开发工具 HBuilder&#xff1a; HBuilderX-高效极客技巧 vscode 1、在vscode中新建一个项目npx degit dcloudio/uni-preset-vue#vite-ts 项目名称 2、在HBuilder中可以可视化进行新建项目 路由 在app.json文件中配置pages路由路径 路由跳转方法 uni.navigateTo(OBJECT)…...

大数据工程师如何做到数据可视化?

好的数据可视化作品都是通过不断的数据对比分析实战出来的。 今天给大家带来一篇大数据工程师干货&#xff0c;从多角度解析做数据可视化的重要性&#xff0c;并解读一些适用的应用场景。大数据工程师们刷到这篇文章时一定要进来看看&#xff0c;满满的干货。 目录 1. 什么是数…...

Java 序列化与反序列化

Java 序列化是一种将对象的状态转换为字节流的机制&#xff0c;以便可以将该对象的状态保存到文件、数据库或通过网络传输。在反序列化过程中&#xff0c;这些字节流可以被重新转换为对象。序列化主要用于以下几种情况&#xff1a; 持久化存储&#xff1a;将对象的状态保存到文…...

自定义防抖注解

问题场景 在开发中由于可能存在的网络波动问题导致用户重复提交&#xff0c;所以自定义一个防抖注解。设计思路&#xff1a;自定义注解加在接口的方法上&#xff0c;注解中设置了SPEL表达式&#xff0c;可以通过SPEL表达式从接口参数中提取Redis的Key&#xff0c;以这个Key作为…...

【尚庭公寓SpringBoot + Vue 项目实战】登录管理(十八)

【尚庭公寓SpringBoot Vue 项目实战】登录管理&#xff08;十八&#xff09; 文章目录 【尚庭公寓SpringBoot Vue 项目实战】登录管理&#xff08;十八&#xff09;1、登录业务介绍2、接口开发2.1、获取图形验证码2.2、登录接口2.3、获取登录用户个人信息 1、登录业务介绍 登…...

【html】用html+css做地表最强王者荣耀辅助工具

源码&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8" /><title></title><style>* {margin: 0;padding: 0;}body{background-color: blue;}.con {width: 300px;height: 500px;background-color: rgba(230,…...

TF-IDF、BM25传统算法总结

1. TF-IDF算法 F-IDF&#xff08;词频-逆文档频率&#xff09;是一种用于衡量文本中词语重要性的方法&#xff0c;特别适用于信息检索和文本挖掘任务。下面会拆分为两部分深入讲解TF-IDF的计算过程&#xff0c;以便更好地理解。 TF-IDF的计算过程可以分为两个主要部分&#xf…...

项目五 OpenStack镜像管理与制作

任务一 理解OpenStack镜像服务 1.1 •什么是镜像 • 镜像通常 是指一系列文件或一个磁盘驱动器的精确副本 。 • 虚拟机 所使用的虚拟磁盘&#xff0c; 实际上是 一种特殊格式的镜像文件 。 • 云 环境下尤其需要 镜像。 • 镜像 就是一个模板&#xff0c;类似于 VMware 的虚拟…...

LabVIEW回热系统热经济性分析及故障诊断

开发了一种利用LabVIEW软件的电厂回热系统热经济性分析和故障诊断系统。该系统针对火电厂回热加热器进行优化&#xff0c;通过实时数据监控与分析&#xff0c;有效提高机组的经济性和安全性&#xff0c;同时降低能耗和维护成本。系统的实施大幅提升了火电厂运行的效率和可靠性&…...

设计模式-迭代器模式

目录 一:基本介绍 二:原理说明 三:案例说明 四:优点 五:缺点 一:基本介绍 1)属于行为模式 2)如果我们的集合元素是用不同的方式实现的,有数组,还有java的集合类,或者还有其他方式,当客户 端要遍历这些集合元素的时候就要使用多种遍历方式,而且还会暴露元素的内部结构,可以…...

UV胶带和UV胶水的应用场景有哪些不同吗?

UV胶带和UV胶水的应用场景有哪些不同吗? UV胶带和UV胶水的应用场景确实存在不同之处&#xff0c;以下是详细的比较和归纳&#xff1a; 一&#xff1a;按使用场景来看&#xff1a; UV胶带的应用场景&#xff1a; 包装行业&#xff1a;UV胶带在包装行业中常用于食品包装、药…...

监控员工上网软件有哪些|4款好用的员工上网行为管理软件推荐

在当今数字化办公环境中&#xff0c;确保网络安全、提升工作效率、以及规范员工上网行为成为企业管理的重要组成部分。 为此&#xff0c;一套高效的员工上网行为管理软件显得尤为关键。 本文将为您推荐五款市场上广受好评的员工上网行为管理软件&#xff0c;帮助您有效监控与管…...

【IPython的使用技巧】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…...

最新AI智能聊天对话问答系统源码(详细图文搭建部署教程)+AI绘画系统(Midjourney),DALL-E3文生图,TTS语音识别输入,文档分析

一、文章前言 随着人工智能技术的持续进步&#xff0c;AI绘画已经发展成为一个日益成熟的领域。越来越多的人开始尝试使用AI绘画软件来创作艺术作品。尽管这些AI绘画软件对绘画领域产生了显著影响&#xff0c;但它们并不会完全取代画师。与传统手绘不同&#xff0c;AI绘画可以…...

项目四 OpenStack身份管理

任务一 理解身份服务 1.1 •Keystone的基本概念 • 认证 &#xff08; Authentication &#xff09; —— 确认 用户身份的过程&#xff0c;又称身份验证 。 • 凭证 &#xff08; Credentials &#xff09; —— 又 称凭据&#xff0c;是用于确认用户身份的数据 。 • 令牌 …...

【后端】websocket学习笔记

文章目录 1. 消息推送常见方式1.1 轮询 VS 长轮询1.2 SSE&#xff08;server-sent event)服务器发送事件 2. websocket介绍2.1 介绍2.2 原理2.3 websoket API2.3.1 客户端【浏览器】API2.3.2 服务端API 3. 代码实现3.1 流程分析3.2 pom依赖3.3 配置类3.4 消息格式3.5 消息类 4.…...

DataWhale - 吃瓜教程学习笔记(一)

学习视频&#xff1a;第1章-绪论_哔哩哔哩_bilibili 西瓜书对应章节&#xff1a; 第一章 & 第二章 文章目录 机器学习三观What&#xff1a;什么是机器学习&#xff1f;Why: 为什么要学机器学习&#xff1f;1. 机器学习理论研究2. 机器学习系统开发3. 机器学习算法迁移 &…...

Attention Is All You Need论文地址

论文地址 点击即可...

如何优雅的一键下载OpenHarmony活跃分支代码?请关注【itopen: ohos_download】

itopen组织&#xff1a;1、提供OpenHarmony优雅实用的小工具2、手把手适配riscv qemu linux的三方库移植3、未来计划riscv qemu ohos的三方库移植 小程序开发4、一切拥抱开源&#xff0c;拥抱国产化 一、概述 为方便大家每次下载OpenHarmony不同分支/tag代码&#xff0c…...

C++初阶-list的底层

目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

vscode(仍待补充)

写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh&#xff1f; debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

Java编程之桥接模式

定义 桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型设计模式&#xff0c;它的核心意图是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过组合关系来替代继承关系&#xff0c;从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...

规则与人性的天平——由高考迟到事件引发的思考

当那位身着校服的考生在考场关闭1分钟后狂奔而至&#xff0c;他涨红的脸上写满绝望。铁门内秒针划过的弧度&#xff0c;成为改变人生的残酷抛物线。家长声嘶力竭的哀求与考务人员机械的"这是规定"&#xff0c;构成当代中国教育最尖锐的隐喻。 一、刚性规则的必要性 …...