diff --git a/docs/assets/images/crypto-decrypt-schematic.png b/docs/assets/images/crypto-decrypt-schematic.png new file mode 100644 index 0000000..862aaf2 Binary files /dev/null and b/docs/assets/images/crypto-decrypt-schematic.png differ diff --git a/docs/assets/images/crypto-instruction.png b/docs/assets/images/crypto-instruction.png new file mode 100644 index 0000000..3a191a1 Binary files /dev/null and b/docs/assets/images/crypto-instruction.png differ diff --git a/docs/guide/2024/index.md b/docs/guide/2024/index.md index 6ed1bc1..ec63b5d 100644 --- a/docs/guide/2024/index.md +++ b/docs/guide/2024/index.md @@ -8,13 +8,17 @@ aside: false ![NewStarCTF 2024](/assets/images/banner-2024.png) +## 赛事背景 + +「没有网络安全,就没有国家安全。」目前我国网民规模已突破 9 亿,成为名副其实的网络大国,网络安全的重要性愈发突出。习近平总书记指出:「网络安全的本质在对抗,对抗的本质在攻防两端能力较量。」为建立高素质网络安全和信息化人才队伍,积极响应国家网络空间安全人才战略,发挥专业优势,发掘网络安全人才,特此发起本活动。 + ## 赛事介绍 -NewStar CTF 2024 是由 13 所高校联合发起的新生入门赛事,比赛持续五周时间,每周更新赛题,以个人赛形式展现,并分设公开赛道和校内赛道。 +NewStar CTF 2024 是由来自 13 所高校的战队联合发起的新生入门赛事,比赛持续五周时间,每周更新赛题,以个人赛形式展现,并分设公开赛道和校内赛道。 在此之前,NewStar 网络安全新生赛已连续举办多届,并一直为各高校提供高质量的新生选拔方案。本届赛事联手春秋杯,以新生的探索能力、知识面、网络安全素养等综合素质为培养目标,致力于挖掘和培养适应新时代新趋势的网络安全新兴力量。本届比赛将取过往之精华,优化比赛难度,使之随时间呈阶梯式上升,并通过题目逐步引导等方式,避免选手大海捞针的情况,以使其能够更专注于知识和技能水平的锻炼。 -比赛采用网络安全靶场赛的形式(传统 Jeopardy 解题模式),动态计分。赛题涵盖 Web、Crypto、Pwn、Reverse、Misc 五大方向,题目的考察范围亦在传统的基础上增加了一些近年来新的构想和思路,做到与时俱进、不断创新。比赛期待各位选手的光临,诚邀任何有兴趣的同学参与。 +比赛采用网络安全靶场赛的形式(传统 Jeopardy 解题模式),动态计分。赛题涵盖 Web、Crypto、Pwn、Reverse、Misc 五大方向,题目的考察范围亦在传统的基础上增加了一些近年来新的构想和思路,做到与时俱进、不断创新。比赛期待各位选手的光临,诚邀任何有兴趣的同学参与。 ## 赛事时间 @@ -24,15 +28,15 @@ NewStar CTF 2024 是由 13 所高校联合发起的新生入门赛事,比赛 ## 赛事群 -公开赛道 QQ 群:1169651901(①群)、806733185(②群) +公开赛道 QQ 群:1169651901(①群)、806733185(②群) -校内赛道 QQ 群:(请联系各校赛事负责人) +校内赛道 QQ 群:994951789(各校赛事群请联系所在院校赛事负责人) ## 组织方式 -### 发起方(战队) +### 主办方 -西安工业大学、中国矿业大学、中国人民公安大学、东北大学秦皇岛分校、海南大学、南京理工大学、广东工业大学、江南大学、浙江师范大学、福建师范大学、中山大学、太原理工大学、中国人民警察大学(以上排名不分先后) +西安工业大学、中国矿业大学、中国人民公安大学、东北大学秦皇岛分校、海南大学、南京理工大学、广东工业大学、江南大学、浙江师范大学、福建师范大学、中山大学、太原理工大学、中国人民警察大学(以上排名不分先后) ### 赞助支持 diff --git a/docs/learn/crypto.md b/docs/learn/crypto.md index 9bda492..15390fa 100644 --- a/docs/learn/crypto.md +++ b/docs/learn/crypto.md @@ -1,260 +1,324 @@ --- titleTemplate: ':title | 快速入门 - NewStar CTF' --- + +# 密码学 +简单来说,密码学是一种用来研究如何加密来保护信息,如何解密获取信息的学问。 ## 为什么学密码 -可以了解 开创并实现现代密码学的RSA算法、未来将抵御量子计算机的格密码等的“后量子密码技术”,以及学到在特殊情况下我们用现代计算机来破解特定的RSA现代密码和后量子密码技术的攻击手段。 +可以了解、开创并实现现代密码学的 RSA 算法、未来将抵御量子计算机的格密码等的「后量子密码技术」,以及学到在特殊情况下我们用现代计算机来破解特定的RSA现代密码和后量子密码技术的攻击手段。 -密码有清晰的路线学习 +密码有清晰的路线学习: -现代密码 +![现代密码学](/assets/images/crypto-instruction.png) -干脆的做题反馈(就跟数学题一样,会就是会,不会就是不会) +并且有干脆的做题反馈,就跟数学题一样,会就是会,不会就是不会。 或者说没有理由,当你入门密码学的时候,就会发现做密码题也会上瘾! +## 准备工作 +你需要准备以下工具: -## 需要的工具 +- PC(一般不限操作系统) +- Python 编程语言和环境 +- yafu 软件 +- 一款笔记软件或网站 +- 草稿纸和笔(随电脑携带的,经常需要演算关系式) +- 大数分解 factordb 网站 -1. 电脑 -2. 软件:`yafu`,`python`,`笔记软件` -3. 草稿纸和笔(随电脑携带的,经常需要演算关系式) -4. 网站 [factordb.com尝试分解n](https://factordb.com/) 、 [探索商城 | NSSCTF](https://www.nssctf.cn/explore/workshop) 、 [RSA入门 | DexterJie'Blog](https://dexterjie.github.io/2024/07/15/非对称加密/RSA/) (大佬的博客,还可以听听歌)等等 +一些帮助性较大的网站: +- 探索商城 | NSSCTF +- CTF Wiki +- OI Wiki(包含一些更深的数学知识) +除此之外,在学习的途中还会遇到很多有意思的工具或网站。 ## 学习路线 -编程:python - -1. 配置好python编译器和集成开发环境(`pycharm`或者`vscode`),`print("hello python world!")` -2. 理解变量和变量类型,变量类型转换 `a = b'65537' a = int(a)` -3. 运算符号,赋值= , 加减乘除 +-*/ ,整除 // ,比较大小 < > <= >= ,等于==,取模 % -4. 基本语法 -5. 循环语句,布尔类型(真和假,1和0,True和False) -6. python列表,数组 -7. pip install 安装`pycyptodome`和`gmpy2`包,模块导入 -8. 函数的使用,`pow(a,b,c)` 相当于 (a ** b) % c -9. python各种进制的格式头(二进制0b,十六进制0x等等) - - +### Python 编程基础 -密码学 +下载 Python,选择一款集成开发环境(IDE,如 [PyCharm](https://www.jetbrains.com/pycharm/) 或 [VSCode](https://visualstudio.microsoft.com/)),并配置好 Python 环境。 -1. RSA公钥加密算法(推荐[探索商城 | NSSCTF](https://www.nssctf.cn/explore/workshop),挺系统的)下面我也会简单介绍RSA公钥加密算法。 +由于国内使用 Python 的包管理工具下载缓慢,可参照 [清华大学软件源 PyPI](https://mirror.tuna.tsinghua.edu.cn/help/pypi/) 配置镜像源。 +使用 Python 的包管理工具安装必要的密码学库: +```bash +pip install pycryptodome +pip install gmpy2 +``` -数学: - -1. 理解模运算 -2. 逆元计算的运用(暂时不要求理解) -3. 理解海纳百川的k和无所不能的公因数 - +在 Python 的学习中,你必须了解: +- 变量和变量类型,变量类型转换 +- 运算符号 +- 基本语法 +- 循环语句 +- 布尔类型 +- 列表和元组 +- 模块导入 +- 函数的使用 +- Python 中各种进制的格式头 +你可以通过解释如下代码片段中高亮行的含义来检验自己的学习情况(下面的代码整体无实际意义): +```python:line-numbers +from Crypto.Util.number import * # [!code highlight] +import gmpy2 +flag = b"flag{test_flag}" +flag = bytes_to_long(flag) # [!code highlight] +e = b'65537' +e = int(a) # [!code highlight] -## 开始学习! +plist = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] # [!code highlight] +plist = tuple(plist) # [!code highlight] -### (一)掌握一定语言基础 +p = getPrime(256) +q = 0xda1a92b4bf451ce51f14a1d178e224a237f3e7e4b18a60084ae7da91889830b1 # [!code highlight] +n = p*q -​ 首先建议学python,密码题经常出现很大的数字和较难的运算,靠手算很难得到答案,所以需要一门计算机语言来帮我们计算。而python是符合直觉的语言,对于新手而言没有过多的条条框框,所以推荐从python入门编程语言,了解一下知识点就行。掌握下面的除画红线的知识点。 +c = pow(flag, e, n) # [!code highlight] -![图来自www.runoob.com](https://gitee.com/saga131/mypic/raw/master/img/image-20240730205109184.png) +x = c % p // 2 # [!code highlight] +``` -讲讲我个人学习python的经历:我一开始就买了本python的入门书籍开始啃,啃到后面for循环就开始做题了,一开始也不会做题,就看别人的writeup(行话解析:看看别人的思路,抄作业,但这是个好的行为,大伙开始都是看过来的),别人的wp(writeup的缩写)一般都会有python代码,就跟着打在自己的电脑上(建议不要直接复制粘贴),遇到不会的就上网搜索,一边学密码学,一边练编程技术。 +### 密码学基础 -### (二)了解`rsa`算法(公钥加密算法) +你需要了解下面这些知识点: -"毫不夸张地说,只要有计算机网络的地方,就有RSA算法。" ——阮一峰 +- 理解模运算 +- 逆元计算的运用(暂时不要求理解) +- RSA 公钥加密算法(可参考文章:[RSA 入门 | DexterJie'Blog](https://dexterjie.github.io/2024/07/15/非对称加密/RSA/)) +- 理解海纳百川的 $k$ 和无所不能的公因数 -#### 1.知识点 +## 开始学习 -- 元素 +### (一)掌握一定语言基础 -​ RSA算法里面一共有 8个元素。 +首先建议学 Python,密码题经常出现很大的数字和较难的运算,靠手算很难得到答案,所以需要一门计算机语言来帮我们计算。而 Python 是较符合人类直觉并且易用的语言,可以快速编写实现一个功能,对于新手而言最为友好,故推荐从 Python 入门编程语言。 -``` -p : 一个素数。 -q : 另一个素数 -n : 由p 和 q 组成的 , 一般为 n = p x q -e : 一个被称为“公钥因子”的数。 -d : 一个被称为“私钥因子”的数。下面的公式会具体展现e和d的转化。 -phi : 一个与n有关,由p,q计算而得到的数。具体就是n的欧拉函数 ϕ(n) 。 -m : 明文,就是要保护的信息。 -c : 密文,就是要破解的信息。下面的公式会具体展现明文和密文的转化。 -``` +对于学习 Python,了解以下知识点即可(摘自 [Python 基础教程 | 菜鸟教程](https://www.runoob.com/python))。 + + + - Python 基础教程 + - Python 简介 + - Python 环境搭建 + - Python 中文编码 + - Python 基础语法 + - Python 变量类型 + - Python 运算符 + - Python 条件语句 + - Python 循环语句 + - Python While 循环语句 + - Python for 循环语句 + - Python 循环嵌套 + - Python break 语句 + - Python continue 语句 + - Python pass 语句 + - Python Number(数组) + - Python 字符串 + - Python List(列表) + - Python 日期和时间 + - Python 函数 + - Python 模块 + + -- 公式 +::: tip 撰稿人注 +讲讲我个人学习 Python 的经历:我一开始就买了本 Python 的入门书籍开始啃,啃到后面 for 循环就开始做题了。一开始也不会做题,就看别人的 WriteUp(看看别人的思路,抄作业,但这是个好的行为,大伙开始都是看过来的),WriteUp 里一般都会有 Python 代码,就跟着打在自己的电脑上(建议不要直接复制粘贴),遇到不会的就上网搜索,一边学密码学,一边练编程技术。 +::: -​ RSA算法中一共由如下公式 +::: tip 编者注 +我具有其它程序语言的基础,对 Python 也只随便看了一些基本的语法(运算、循环)之后就上手了。刚开始做题很艰难,几乎写每一行功能性代码都要网上去搜索(诸如用什么库、函数),经历过大约半个月的持续边做题边编程、看 WriteUp、赛后与前辈交流,Python 能力也见长了。遇到不会的立即学习并应用,慢慢地也就无师自通了。 +::: -​ 1.加密公式 -$$ -c = m^{e} \pmod n -$$ -​ 2.解密公式 -$$ -m = c^{d} \pmod n -$$ +### (二)了解 RSA 算法(公钥加密算法) + +「毫不夸张地说,只要有计算机网络的地方,就有 RSA 算法。」 +
——阮一峰
+
-​ 3.e和d的关系式 -$$ -d = e^{-1} \pmod {phi} -$$ -​ 4.p和q是素数的情况下,n的欧拉函数phi -$$ -phi = (p-1)*(q-1) -$$ -​ 5.n与p,q的关系式 -$$ -n = p*q -$$ -​ 6.大小关系 +#### 1. 元素 -​ -$$ -m^e < n \\ -n \approx phi -$$ +RSA 算法里面一共有 8 个元素。 +- $p$,一个素数。 +- $q$,另一个素数 +- $n$,根据 $p$ 和 $q$ 形成的数,一般为 $n = p \times q$ +- $e$,一个被称为「公钥因子」的数 +- $d$,一个被称为「私钥因子」的数。下面的公式会具体展现e和d的转化 +- $\varphi$,一个与 $n$ 有关,由 $p$ 和 $q$ 计算而得到的数。具体就是 $n$ 的欧拉函数 $\varphi(n)$ +- $m$,明文,就是要保护的信息。 +- $c$,密文,就是要破解的信息。 -``` - 入门后可以尝试推导一下上面的公式,入门前只需要懂得如何在python中实现上面公式即可。 -``` +下面的公式会具体展现明文和密文的转化。 +#### 2. 公式 +RSA算法中有以下公式 -- 原理 +1. 加密公式 - - 解密原理 +$$ c = m^{e} \pmod n $$ - 一般RSA算法加密会公开公钥n和e,信息传输难免会泄露密文c,所以我们可以得到的一共有三个元素n,e,c。从上面的解密公式可以知道我们需要密钥因子d,而计算d需要e和phi,e已知,求未知的phi又需要p和q,有关p和q的式子只有一个$n=p*q$ +2. 解密公式 - +$$ m = c^{d} \pmod n $$ - 因此解密的关键是在得到p和q +3. $e$ 和 $d$ 的关系式 - ![解密原理](https://gitee.com/saga131/mypic/raw/master/img/解密原理.png) +$$ d = e^{-1} \pmod{\varphi} $$ - +4. $p$ 和 $q$ 是素数的情况下,$n$ 的欧拉函数 - - 难破解的原理 +$$ \varphi = (p-1)(q-1) $$ - RSA算法开创了现代密码并实现了非对称加密,其中难破解的原理基于大整数分解。 +5. $n$ 与 $p, q$ 的关系式 - ​ 计算n = p*q简单,但由n分解出p,q +$$ n = p \times q $$ - ​ 手算 12 的因子,很快可以列出 [1,2,3,4,6,12],但一旦上升到很大的整数,例如 - - ```python - 6969872410035233098344189258766624225446081814953480897731644163180991292913719910322241873463164232700368119465476508174863062276659958418657253738005689 - ``` +1. 大小关系 - ​ 就根本拆不开成两个数字。 +$$ +m^e < n \\ +n \approx \varphi +$$ - +::: tip +入门后可以尝试推导一下上面的公式,入门前只需懂得如何在 Python 中实现上面公式即可。 +::: - - 我们解题的原理 +#### 3. 原理 - 上面说到,n很难分解,那我们是靠什么来破解的呢? - - 答:靠一个个特殊的情况,有时候出题人会给出泄露的d,或者p和q之间的关系让我们数学推导等等特殊情况。针对这一个个特殊情况,我们也有相应的攻击方法(如下)。 +- 解密原理 -​ ![image-20240801121847541](https://gitee.com/saga131/mypic/raw/master/img/image-20240801121847541.png) + 一般 RSA 算法加密会公开公钥 $n$ 和 $e$,信息传输难免会泄露密文 $c$,所以我们可以得到的一共有三个元素 $n, e, c$. 从上面的解密公式可以知道我们需要密钥因子 $d$,而计算 $d$ 需要 $e$ 和 $\varphi$,$e$ 已知,求未知的 $\varphi$ 又需要 $p$ 和 $q$,有关 $p$ 和 $q$ 的式子只有一个 $n = p \times q$. -​ + 因此解密的关键是在得到 $p$ 和 $q$. + ![解密原理](/assets/images/crypto-decrypt-schematic.png) +- 难破解的原理 + RSA 算法开创了现代密码并实现了非对称加密,其中难破解的原理基于[大整数分解](https://zh.wikipedia.org/wiki/%E6%95%B4%E6%95%B0%E5%88%86%E8%A7%A3)。 + 计算 $n = p \times q$ 简单,但由 $n$ 分解出 $p, q$ 非常困难,这是 RSA 算法的基础。 -- 数学基础 + 对于较小的整数,手算数 $12$ 的因子,很快可以列出 $1,2,3,4,6,12$,但一旦上升到很大的整数,例如 6969872410035233098344189258766624225446081814953480897731644163180991292913719910322241873463164232700368119465476508174863062276659958418657253738005689,就极难拆成两个数字。 - RSA中涉及到我们之前没有或者说不太重视的一些数学知识点,接下来我们一起来学习一下。 +- 解题的原理 - - 取模 + 上面说到,$n$ 很难分解,那我们是靠什么来破解的呢? - ​ 上面公式四个有三个都出现了一个英文单词 mod ,这可不是游戏中打mod的意思 , 在数学中,这被称为 “模” ,数学符号是这个`%`,相信大家小时候都学过余,这个就是模。12除5余2的余。接下来讲一种新的观点,12在 $\mod 5$ 的世界中就是2 ,这个世界的数学范围是[ 0 , 5 ) 。 + 答:靠一个个特殊的情况,有时候出题人会给出泄露的 $d$,或者 $p$ 和 $q$ 之间的关系让我们数学推导等等特殊情况。针对这一个个特殊情况,我们也有相应的攻击方法,例如: - + - 小明文攻击 + - 低指数暴力破解 + - Rabin 攻击与中国剩余定理的初始应用 + - 小明文攻击 + - 广播攻击 + - 低加密指数 + - 不互素的CRT + - 拓展欧拉定理 + - Rabin 进阶 + - dp & dq 泄露 + - $p-1$ 光滑 + - AMM + - RSA 证书 + - 手动处理 + - 代码处理 + - 变种 RSA — SchmidtSamoa + - 复数与 RSA - - 模运算 +#### 4. 数学基础 - ​ 模运算和平时的运算基本上没有太大区别,只是在模运算中,我们人为的划定了一个集合[ 0 , n ) ,其中出现的数字都不会超过这个集合。模运算也可以实现等式左右两边交换,例如e和d的关系式也可以写成 $e*d = 1 \pmod n$ 。 +RSA 中涉及到我们之前没有或者说不太重视的一些数学知识点,接下来我们一起来学习一下。 - ​ 而运算符号加减乘除的除就有些变化了。上面的$e^{-1}$ 可以写成 $\frac {1}{e}$ ,也就是1除于e,但在模运算中不能直接除, +- 取模 - 例如 $\frac {a+1}{b-1} \pmod n $ 要先求b的逆元 $(b-1)^{-1}$,再将这逆元$(b-1)^{-1}$与$(a+1)$相乘。 + 上面公式四个有三个都出现了一个英文单词 mod,在数学中,这被称为「模」,是一种运算,即求余运算,编程语言中常以 `%` 展现。例如,$17 \div 5 = 3 \cdots 2$,则 `17 % 5 = 2`,或者记作 $17 \equiv 2 \pmod 5$. 很容易发现,$17 \pmod 5$ 的值域只有 $[0,5)$ 中的整数。 - ​ 在上面第三个公式 e和d的关系式中有$$d^{-1}$$,这涉及到模运算中求逆元,这点展开会涉及到其他数学知识,这里先放着不谈。只要记住在模运算中,没有除法,只有求逆元然后再相乘。具体的代码实现会在下面讲述。 +- 模运算 - + 模运算和平时的运算基本上没有太大区别,只是在模运算中,我们人为的划定了一个整数集合 $[0, n)$,模运算结果都不会超过这个集合。模运算也可以实现等式左右两边交换,例如 $e$ 和 $d$ 的关系式也可以写成 $e\times d = 1 \pmod n$. - - 海纳百川的k和无所不能的公因数 + 而运算符号加减乘除的除就有些变化了。上面的 $e^{-1}$ 可以写成 $\frac {1}{e}$,但在模运算中不能直接除, - ​ 在上面的取模和模运算中,涉及到大量的$$\mod n$$ ,如何转化成可以手算推理的东西呢? + 例如 $\frac {a+1}{b-1} \pmod n$ 要先求b的逆元 $(b-1)^{-1}$,再将这逆元 $(b-1)^{-1}$ 与 $(a+1)$ 相乘。 - ​ 答:$k*n$ 其中k是任意整数,例如 $12 \pmod 5 = 12 - 2*5$ 其中的2就是k啦。 + 在上面第三个公式 $e$ 和 $d$ 的关系式中有 $d^{-1}$,这涉及到模运算中求逆元,这点展开会涉及到其他数学知识,这里先放着不谈。只要记住在模运算中,没有除法,只有求逆元然后再相乘。具体的代码实现会在下面讲述。 - ​ 我们之后会遇到一部分的数学推导题,出题人会给出有关p和q的关系式。草稿纸上推理处理完关系式后,经常能得到一个有关p或者q的式子$a = b \pmod p$,此时我们只需要将这个式子转化一下 $a = b+k_1*p$ 即 $k_1*p = a-b$ 求 `a-b` 和 `n` 的公因数就可以得到p了,因为$n = p*q$ 也可以看成 $ n = k_2*p$,而$k_1$一般不等于$k_2$ 所以就可以得到p。具体情况请见[羊城杯 2021Bigrsa](https://www.cnblogs.com/Clair-is-com/p/16470121.html) 共享素数。 +- 海纳百川的 $k¥ 和无所不能的公因数 -​ + 在上面的取模和模运算中,涉及到大量的 $\mathrm{mod}\ n$ 操作,如何转化成可以手算推理的东西呢? + 答:$k \times n$,其中 $k$ 是任意整数,例如 $12 \pmod 5 = 12 - 2 \times 5$,其中 $k=2$. + 我们之后会遇到一部分的数学推导题,题目会给出有关 $p$ 和 $q$ 的关系式。草稿纸上推理处理完关系式后,经常能得到一个有关 $p$ 或者 $q$ 的式子 $a = b \pmod p$,此时我们只需要将这个式子转化一下 + $$a = b + k_1 p \Rightarrow k_1 p = a - b$$ + 然后求 $a-b$ 和 $n$ 的公因数就可以得到 $p$ 了。 + 因为 $n = p \times q$ 也可以看成 $n = k_2 p$,而一般 $k_1 \ne k_2$,所以就可以得到 $p$. + ::: tip + 具体情况可参见 [羊城杯 2021 Bigrsa](https://www.cnblogs.com/Clair-is-com/p/16470121.html) 共享素数。 + ::: -- 计算机基础 - - 把`“我喜欢密码学”`转化为`整数`——**编码** +#### 5. 计算机基础 -​ 这看起来有点不可思议,文字和数字怎么联系在一起,但计算机上就可以,计算机底层是一堆二进制,只有0和1 。要想在屏幕 上展现文字,需要”编码“,编码将数字按照规定的表转换成对应的文字,常见的编码有ASCII表。 + 思考这样一个问题:将字符串 `我喜欢密码学` 转化为整数。 -![图来自www.runoob.com](https://gitee.com/saga131/mypic/raw/master/img/image-20240801123920601.png) + 这看起来有点不可思议,文字和数字怎么联系在一起。但计算机上就可以,计算机底层是一堆二进制,只有 `0` 和 `1` 。要想在屏幕上展现文字,就需要**编码**。编码将数字按照一定的法则转换成对应的文字,常见的编码如 [ASCII 编码](https://www.runoob.com/w3cnote/ascii.html)。 -有了编码,我们就能把想保护传输的信息转换成整数,再通过RSA算法加密计算得到密文c。 -$$ -c = m^{e} \pmod n -$$ + 通过一些编码方式,我们就能把想保护传输的信息转换成整数并一一对应,再通过 RSA 算法加密计算得到密文 $c$. + $$ c = m^{e} \pmod n $$ +#### 6. 代码实现 -#### 2.代码实现 +加密脚本不需要掌握熟背,只需知道每一行的意思即可;解密脚本需熟练掌握。 -- 加密脚本(不需要掌握熟背,只用知道每一行是什么意思就行) +::: code-group -```python -# 导入Crypto.Util.number模块中的所有函数 +```python:line-numbers [RSA 加密脚本] +# 导入 Crypto.Util.number 模块中的所有函数 from Crypto.Util.number import * -# 导入gmpy2模块,用于高性能的数学运算 +# 导入 gmpy2 模块,用于高性能的数学运算 import gmpy2 -# 从秘密模块导入flag,通常这是CTF挑战中的隐藏信息 -from 秘密 import flag +# 从 secret 模块导入 flag,通常用于表示隐藏信息 +from secret import flag -# 这是给出了flag的样式,并不是真正的flag,但已经提供了一些提示,有些题目会根据flag头来破解 -flag = b"saga131{******}" +# 这是给出了 flag 的样式,并不是真正的 flag,但已经提供了一些提示,有些题目会根据 flag 头来破解 +flag = b"NSCTF{******}" # 生成两个256位的质数p和q p = getPrime(256) q = getPrime(256) # 计算n,即p和q的乘积,用于RSA算法的模数 +<<<<<<< HEAD +n = p * q +======= n = p*q +>>>>>>> a45c34ff209a4c248d7650e232fa17e26ff8d5a3 # 定义公钥指数e,通常为65537 e = 65537 # 将flag转换为长整数 @@ -273,6 +337,19 @@ print(f'c = {c}') print(f'p = {p}') # 打印质数q(通常在CTF中不会直接给出) print(f'q = {q}') +<<<<<<< HEAD + +# 以下是输出的结果,这些值通常在 CTF 题目中给出 +# n = 4024941574680124502316363981547051098032677531528457166859670261861728313081282635664023890534034586556845494323497683923813915739234466472396261320600483 +# e = 65537 +# c = 226967182640114431119923862488626190608050511354278604627242247124377735518111678279381846350389469161980779137969837090666693533616114290831130137310320 +# p = 62658315832909660478685872111870233686035497063073558738980225214351386198939 +# q = 64236351092062515945998729497153532140067861836088195242257976217499252460697 +``` + +```python:line-numbers [RSA 解密脚本] +# 导入 Crypto.Util.number 模块中的所有函数,用于处理数字和字节之间的转换等 +======= """ # 以下是打印的结果,这些值通常在CTF挑战中给出 n = 4024941574680124502316363981547051098032677531528457166859670261861728313081282635664023890534034586556845494323497683923813915739234466472396261320600483 @@ -287,6 +364,7 @@ q = 6423635109206251594599872949715353214006786183608819524225797621749925246069 ```python # 导入Crypto.Util.number模块中的所有函数,用于处理数字和字节之间的转换等 +>>>>>>> a45c34ff209a4c248d7650e232fa17e26ff8d5a3 from Crypto.Util.number import * @@ -304,6 +382,15 @@ q = 6423635109206251594599872949715353214006786183608819524225797621749925246069 """处理部分""" +<<<<<<< HEAD +# 计算欧拉函数 phi(n),用于RSA算法中的私钥计算 +phi = (p-1)*(q-1) +# 计算私钥指数 d ,即 e 在模 phi(n) 的逆元 +d = inverse(e,phi) +# 使用私钥指数 d 解密密文 c,得到明文 m,具体就是 m = c**d (modn) +m = pow(c, d, n) +# 将解密后的长整数 m 转换回字符串,得到原始的 flag 信息 +======= # 计算欧拉函数φ(n),用于RSA算法中的私钥计算 phi = (p-1)*(q-1) # 计算私钥指数d,即 e在模φ(n)的逆元 @@ -311,10 +398,26 @@ d = inverse(e,phi) # 使用私钥指数d解密密文c,得到明文m 具体就是 m = c**d (modn) m = pow(c,d,n) # 将解密后的长整数m转换回字符串,得到原始的flag信息 +>>>>>>> a45c34ff209a4c248d7650e232fa17e26ff8d5a3 flag = long_to_bytes(m) """输出部分""" +<<<<<<< HEAD +# 打印解密后的 flag 信息 +print(flag) +``` + +::: + +## 以后的路 + +入门 RSA 算法后,可以选择跟着 [NSSCTF 的工坊课程](https://www.nssctf.cn/explore/workshop/) 自主继续深造 RSA,在这基础上一起学习 AES 对称加密、圆锥曲线算法、LCG 流密码、格密码和 DSA 密码等等。 + +::: tip 写在最后 +密码路上道阻且长,希望同学们能坚持下去,必定能见到密码学的彩虹! +::: +======= # 打印解密后的flag信息 print(flag) ``` @@ -330,3 +433,4 @@ print(flag) ## 写在最后的话 密码路上道阻且长,希望兄弟们能坚持下去,必定能见到密码学的彩虹! +>>>>>>> a45c34ff209a4c248d7650e232fa17e26ff8d5a3 diff --git a/docs/learn/index.md b/docs/learn/index.md index 7fc521c..012db7f 100644 --- a/docs/learn/index.md +++ b/docs/learn/index.md @@ -15,28 +15,32 @@ import 'element-plus/es/components/tag/style/css' ## 什么是 CTF -CTF 是一种比赛形式,你会得到一个题面(可能是一段话、一个压缩包、一张图片、一个网站、一个链接、一份源码、一个程序等),你需要根据题面,通过各种手法找到或得到诸如 `flag{xxx}` 的内容,这便是此题的答案。 +CTF 是一种比赛形式,你会得到一个题面(可能是一段话、一个压缩包、一张图片、一个网站、一个链接、一份源码、一个程序等),你需要根据题面,通过各种手法找到或得到诸如 `flag{xxx}` 的内容,这便是此题的答案。 ## 走出洞穴的第一步 +如果你还没有掌握一门编程语言,建议先从编程语言入手,C 语言或者 Python,培养对编程的感觉。只要你掌握了一门语言,再学习其他语言能够触类旁通。 + 如果你此前从未接触过 CTF,你可能需要先了解其形式,即通过一些在线靶场或新生赛的低门槛题目进行适应。下面的一些公益新生赛事或平台或许会对你有所帮助: -- 赛事 西电 MoeCTF -- 赛事 BaseCTF -- 平台 CTFHub -- 平台 CTFSHOW -- 平台 BUUOJ -- 平台 NSSCTF +- 赛事 西电 MoeCTF +- 赛事 BaseCTF +- 平台 CTFHub +- 平台 CTFSHOW +- 平台 BUUOJ +- 平台 NSSCTF 随后,你应当选定一个方向,作为你主攻方向。例如,对网络感兴趣、有基础的同学可能更适合 Web 方向,而对程序运行底层逻辑、二进制感兴趣的可能更适合逆向(Reverse)和 Pwn,等等。 然后,当你接触到特定的题目时,你会遇到特定的知识点。设计得当的引导会控制好你所接触的「新事物」的量。这个时候,辅以实践,你再通过搜索、询问等各种方式学习知识细节,或许会轻松许多。 +如果你在寻求更细节和全面的指导,可以查看 [CTF Wiki](https://ctf-wiki.org/) 或由探姬师傅主导的 [Hello CTF](https://hello-ctf.com/) 等网站。注意,与传统的课堂教育模式不同,这些网站并不要求你立即并全部掌握其中的内容,而是充当一个手册供你速查。 + 对于自己无能为力的题,记得在赛后根据题解(WriteUp)进行复现。温故而知新,可以为师矣。 ## 我还没有准备好 - + 参与 CTF 赛事,是一个不断在历练中成长的过程,是对自我螺旋上升式的提升,是理论与实践相结合的又一深入尝试。请时刻铭记:充分发挥自己的主观能动性,在实践中成长。 @@ -57,4 +61,4 @@ CTF 是一种比赛形式,你会得到一个题面 -import Link from '@/components/docs/Link.vue' - -# Reverse +# 逆向工程 逆向工程通常是在没有源代码的情况下对软件进行分析,相对于正向的代码编程来说,逻辑通常是反过来的,需要有好的代码分析和反向思维能力。 @@ -13,10 +10,10 @@ import Link from '@/components/docs/Link.vue' C 语言是逆向工程的基础,务必重点学习以下内容。 -1. 流程控制: if、switch、goto、break -2. 指针操作: 引用,解引用,取地址,数组与指针转化 -3. 数据类型: 熟记 char、int、int64 等类型大小 -4. 可逆运算: 异或运算、算数运算、移位与循环移位运算 +1. 流程控制:if、switch、goto、break +2. 指针操作:引用,解引用,取地址,数组与指针转化 +3. 数据类型:熟记 char、int、int64 等类型大小 +4. 可逆运算:异或运算、算数运算、移位与循环移位运算 ## 0x02. 学习常见加密 @@ -24,11 +21,11 @@ C 语言是逆向工程的基础,务必重点学习以下内容。 1. TEA 系列加密: TEA、XTEA、XXTEA 2. RC4 加密 -3. AES/DES加密 -4. 16进制编码 -5. Base64编码 +3. AES/DES 加密 +4. 16 进制编码 +5. Base64 编码 -加密特征识别可参阅:常见加密算法特征识别 +加密特征识别可参阅:[常见加密算法特征识别](https://pangbai.work/IT/re/ctf_encode/) 常见加密不是一成不变的模板,死记硬背不可能通杀,请务必读懂加密过程和大致原理。 diff --git a/docs/learn/web.md b/docs/learn/web.md index a3d451b..12f8fd4 100644 --- a/docs/learn/web.md +++ b/docs/learn/web.md @@ -14,7 +14,7 @@ CTF 中的 Web 方向通常指的是通过阅读阅读网站源码,或是根 ## 收拾行李 -Web 方向需要有较强的代码阅读能力(即便是未接触过的代码,不要求会写,但需能够阅读),以及搜索能力。 +Web 方向需要有较强的代码阅读能力(即便是未接触过的代码,不要求会写,但需能够阅读),以及搜索能力。 以下建议可能能够帮助你提升代码阅读能力,但任何事物都是循序渐进的,你也可以在做题的同时学习和成长。 - 学习和掌握 Python 语言 diff --git a/package.json b/package.json index 7307c2e..f3963f7 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "element-plus": "^2.8.1", "markdown-it-mathjax3": "^4.3.2", "nodemon": "^3.1.4", - "sass": "^1.77.8", + "sass": "~1.76.0", "unplugin-element-plus": "^0.8.0", "vitepress": "^1.3.1", "vue": "^3.4.35", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 961f164..e6007cb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -31,14 +31,14 @@ importers: specifier: ^3.1.4 version: 3.1.4 sass: - specifier: ^1.77.8 - version: 1.77.8 + specifier: ~1.76.0 + version: 1.76.0 unplugin-element-plus: specifier: ^0.8.0 version: 0.8.0(rollup@4.20.0) vitepress: specifier: ^1.3.1 - version: 1.3.1(@algolia/client-search@4.24.0)(@types/node@22.1.0)(async-validator@4.2.5)(markdown-it-mathjax3@4.3.2)(postcss@8.4.41)(sass@1.77.8)(search-insights@2.15.0)(typescript@5.5.4) + version: 1.3.1(@algolia/client-search@4.24.0)(@types/node@22.1.0)(async-validator@4.2.5)(markdown-it-mathjax3@4.3.2)(postcss@8.4.41)(sass@1.76.0)(search-insights@2.15.0)(typescript@5.5.4) vue: specifier: ^3.4.35 version: 3.4.35(typescript@5.5.4) @@ -937,8 +937,8 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - sass@1.77.8: - resolution: {integrity: sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==} + sass@1.76.0: + resolution: {integrity: sha512-nc3LeqvF2FNW5xGF1zxZifdW3ffIz5aBb7I7tSvOoNu7z1RQ6pFt9MBuiPtjgaI62YWrM/txjWlOCFiGtf2xpw==} engines: {node: '>=14.0.0'} hasBin: true @@ -1468,9 +1468,9 @@ snapshots: dependencies: '@types/node': 22.1.0 - '@vitejs/plugin-vue@5.1.2(vite@5.4.2(@types/node@22.1.0)(sass@1.77.8))(vue@3.4.35(typescript@5.5.4))': + '@vitejs/plugin-vue@5.1.2(vite@5.4.2(@types/node@22.1.0)(sass@1.76.0))(vue@3.4.35(typescript@5.5.4))': dependencies: - vite: 5.4.2(@types/node@22.1.0)(sass@1.77.8) + vite: 5.4.2(@types/node@22.1.0)(sass@1.76.0) vue: 3.4.35(typescript@5.5.4) '@volar/language-core@2.4.0-alpha.18': @@ -2050,7 +2050,7 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.20.0 fsevents: 2.3.3 - sass@1.77.8: + sass@1.76.0: dependencies: chokidar: 3.6.0 immutable: 4.3.7 @@ -2129,7 +2129,7 @@ snapshots: valid-data-url@3.0.1: {} - vite@5.4.2(@types/node@22.1.0)(sass@1.77.8): + vite@5.4.2(@types/node@22.1.0)(sass@1.76.0): dependencies: esbuild: 0.21.5 postcss: 8.4.41 @@ -2137,16 +2137,16 @@ snapshots: optionalDependencies: '@types/node': 22.1.0 fsevents: 2.3.3 - sass: 1.77.8 + sass: 1.76.0 - vitepress@1.3.1(@algolia/client-search@4.24.0)(@types/node@22.1.0)(async-validator@4.2.5)(markdown-it-mathjax3@4.3.2)(postcss@8.4.41)(sass@1.77.8)(search-insights@2.15.0)(typescript@5.5.4): + vitepress@1.3.1(@algolia/client-search@4.24.0)(@types/node@22.1.0)(async-validator@4.2.5)(markdown-it-mathjax3@4.3.2)(postcss@8.4.41)(sass@1.76.0)(search-insights@2.15.0)(typescript@5.5.4): dependencies: '@docsearch/css': 3.6.1 '@docsearch/js': 3.6.1(@algolia/client-search@4.24.0)(search-insights@2.15.0) '@shikijs/core': 1.12.1 '@shikijs/transformers': 1.12.1 '@types/markdown-it': 14.1.2 - '@vitejs/plugin-vue': 5.1.2(vite@5.4.2(@types/node@22.1.0)(sass@1.77.8))(vue@3.4.35(typescript@5.5.4)) + '@vitejs/plugin-vue': 5.1.2(vite@5.4.2(@types/node@22.1.0)(sass@1.76.0))(vue@3.4.35(typescript@5.5.4)) '@vue/devtools-api': 7.3.7 '@vue/shared': 3.4.35 '@vueuse/core': 10.11.0(vue@3.4.35(typescript@5.5.4)) @@ -2155,7 +2155,7 @@ snapshots: mark.js: 8.11.1 minisearch: 7.1.0 shiki: 1.12.1 - vite: 5.4.2(@types/node@22.1.0)(sass@1.77.8) + vite: 5.4.2(@types/node@22.1.0)(sass@1.76.0) vue: 3.4.35(typescript@5.5.4) optionalDependencies: markdown-it-mathjax3: 4.3.2 diff --git a/theme-config.yml b/theme-config.yml index 0538972..3f1c604 100644 --- a/theme-config.yml +++ b/theme-config.yml @@ -22,6 +22,8 @@ sidebar: link: /learn/web - text: Reverse link: /learn/reverse + - text: Crypto + link: /learn/crypto '/guide/2024/': - text: 参考文档 diff --git a/theme/assets/fonts/docs/font.eot b/theme/assets/fonts/docs/font.eot new file mode 100644 index 0000000..24557df Binary files /dev/null and b/theme/assets/fonts/docs/font.eot differ diff --git a/theme/assets/fonts/docs/font.svg b/theme/assets/fonts/docs/font.svg new file mode 100644 index 0000000..041d231 --- /dev/null +++ b/theme/assets/fonts/docs/font.svg @@ -0,0 +1,11 @@ + + + +Generated by IcoMoon + + + + + + + \ No newline at end of file diff --git a/theme/assets/fonts/docs/font.ttf b/theme/assets/fonts/docs/font.ttf new file mode 100644 index 0000000..dbec07f Binary files /dev/null and b/theme/assets/fonts/docs/font.ttf differ diff --git a/theme/assets/fonts/docs/font.woff b/theme/assets/fonts/docs/font.woff new file mode 100644 index 0000000..ef5cd48 Binary files /dev/null and b/theme/assets/fonts/docs/font.woff differ diff --git a/theme/assets/fonts/docs/map.scss b/theme/assets/fonts/docs/map.scss new file mode 100644 index 0000000..1b33851 --- /dev/null +++ b/theme/assets/fonts/docs/map.scss @@ -0,0 +1,3 @@ +$map: ( + "external": "\1f517" +); \ No newline at end of file diff --git a/theme/assets/fonts/docs/style.scss b/theme/assets/fonts/docs/style.scss new file mode 100644 index 0000000..8a27671 --- /dev/null +++ b/theme/assets/fonts/docs/style.scss @@ -0,0 +1,31 @@ +@font-face { + font-family: "vp-docs"; + src: url("./font.eot?inpve4"); + src: url("./font.eot?inpve4#iefix") format("embedded-opentype"), + url("./font.ttf?inpve4") format("truetype"), url("fonts/font.woff?inpve4") format("woff"), + url("./font.svg?inpve4#icomoon") format("svg"); + font-weight: normal; + font-style: normal; + font-display: block; +} + +.icon--docs[class^="icon-"], +.icon--docs[class*=" icon-"] { + /* use !important to prevent issues with browser extensions that change fonts */ + font-family: "vp-docs" !important; + speak: never; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + color: currentColor; + + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.icon-external:before { + content: "\1f517"; +} diff --git a/theme/assets/fonts/package.scss b/theme/assets/fonts/package.scss new file mode 100644 index 0000000..cd76014 --- /dev/null +++ b/theme/assets/fonts/package.scss @@ -0,0 +1,40 @@ +$font-name: "example"; +$font-family: "vp-example"; + +@mixin register-font($name: $font-name, $family: $font-family) { + @font-face { + font-family: $family; + src: url("./#{$name}/font.eot?inpve4"); + src: url("./#{$name}/font.eot?inpve4#iefix") format("embedded-opentype"), + url("./#{$name}/font.ttf?inpve4") format("truetype"), url("fonts/font.woff?inpve4") format("woff"), + url("./#{$name}/font.svg?inpve4#icomoon") format("svg"); + font-weight: normal; + font-style: normal; + font-display: block; + } +} + +@mixin inject-font($family: $font-family) { + & { + /* use !important to prevent issues with browser extensions that change fonts */ + font-family: $family !important; + speak: never; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + color: currentColor; + + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } +} + +@mixin apply-font($name: $font-name, $family: $font-family) { + &.icon--#{$name}[class^="icon-"], + &.icon--#{$name}[class*=" icon-"] { + @include inject-font($family); + } +} diff --git a/theme/components/docs/Link.vue b/theme/components/docs/Link.vue index b6ee360..0a8dc0d 100644 --- a/theme/components/docs/Link.vue +++ b/theme/components/docs/Link.vue @@ -3,7 +3,7 @@ withDefaults( defineProps<{ href?: string; target?: string; - icon?: keyof typeof iconMap; + icon?: string /* keyof typeof iconMap */; iconPos?: "left" | "right"; /** * Theme of the link @@ -21,28 +21,37 @@ withDefaults( ); function fmtClass(theme?: string, ...append: string[]): string { let classes: string[] = []; - if (append) classes.push(...append); if (!theme) theme = ""; theme.split(/\s+/).forEach(t => { - classes.push(`link-${t}`); + t && classes.push(`link-${t}`); }); + if (append) classes.push(...append); return classes.join(" "); } -const iconMap = { - external: `External link icon` -}; + +// const iconMap = { +// external: `` +// }; diff --git a/theme/style.scss b/theme/style.scss index b8dc35f..308ccf0 100644 --- a/theme/style.scss +++ b/theme/style.scss @@ -9,10 +9,24 @@ :root { --index-logo: url('@/assets/images/ns_blue.svg'); + + --vp-c-text-1: rgb(60, 60, 60); + + .desc-text { + --vp-c-text-1: rgb(145, 145, 145); + color: var(--vp-c-text-1); + } } .dark { --index-logo: url('@/assets/images/ns_orange.svg'); + + --vp-c-text-1: rgb(235, 235, 235); + + .desc-text { + --vp-c-text-1: rgb(165, 165, 165); + color: var(--vp-c-text-1); + } } /** diff --git a/theme/styles/docs-link-adjust.scss b/theme/styles/docs-link-adjust.scss index 28b337f..ff2d8ae 100644 --- a/theme/styles/docs-link-adjust.scss +++ b/theme/styles/docs-link-adjust.scss @@ -1,13 +1,13 @@ -@use "./utils/docs-link.scss" as *; +@use "./utils/docs-link-app.scss" as link; +@use "@/assets/fonts/docs/map.scss" as docs-map; .vp-doc a:not([data-link]), .vp-doc a[data-link="false"] { &:not(.header-anchor) { - text-decoration: none; - color: var(--vp-c-brand-1); - @include underline-normal; - &:hover { - color: var(--vp-c-brand-2); + @include link.underline_blink(currentColor, var(--vp-c-brand-1)); + &[href*="://"] + { + @include link.icon_with_name("docs", "vp-docs", docs-map.$map, "external", "right"); } } } diff --git a/theme/styles/utils/docs-link-app.scss b/theme/styles/utils/docs-link-app.scss new file mode 100644 index 0000000..30f9b53 --- /dev/null +++ b/theme/styles/utils/docs-link-app.scss @@ -0,0 +1,141 @@ +/** Application */ +@use "@/styles/utils/docs-link.scss" as *; +@use "@/assets/fonts/package.scss" as font; + +@mixin plain($color: var(--vp-c-brand-1), $hover: var(--vp-c-brand-2)) { + text-decoration: none; + color: $color !important; + &:hover { + color: $hover !important; + } +} + +@mixin underline_always($color: var(--vp-c-brand-1), $hover: var(--vp-c-brand-2)) { + @include plain($color, $hover); + + @include underline-bg-color(currentColor, transparent); + @include underline-bg-width(100%, 0%); + @include underline-bg-posX(0%, 100%); +} + +@mixin underline_hover($color: var(--vp-c-brand-1), $hover: var(--vp-c-brand-2)) { + // @include underline_always($color, $hover); + @include plain($color, $hover); + + transition: color ease-in-out 0.25s, background-size ease-in-out 0.25s; + @include underline-bg-color(currentColor, transparent); + @include underline-bg-width(0%, 100%); + @include underline-bg-posX(100%, 0%); + &:hover, + &:active { + @include underline-bg-width(100%, 0%); + @include underline-bg-posX(0%, 100%); + } +} + +@mixin underline_blink($color: var(--vp-c-brand-1), $hover: var(--vp-c-brand-2)) { + // @include underline_always($color, $hover); + @include plain($color, $hover); + + transition: color ease-in-out 0.25s, background-color ease-in-out 0.25s; + @include underline-bg-color(currentColor, transparent); + @include underline-bg-width(100%, 0%); + @include underline-bg-posX(0%, 100%); + &:hover, + &:active { + animation: underline-blink 0.5s ease-in-out; + } + + @keyframes underline-blink { + 0% { + @include underline-bg-width(100%, 0%); + @include underline-bg-posX(100%, 0%); + } + 50% { + @include underline-bg-width(0%, 100%); + @include underline-bg-posX(100%, 0%); + } + 51% { + @include underline-bg-width(0%, 100%); + @include underline-bg-posX(0%, 100%); + } + 100% { + @include underline-bg-width(100%, 0%); + @include underline-bg-posX(0%, 100%); + } + } +} + +@mixin underline($style: "always", $color: var(--vp-c-brand-1), $hover: var(--vp-c-brand-2)) { + @if $style == "always" { + @include underline_always($color, $hover); + } @else if $style == "hover" { + @include underline_hover($color, $hover); + } @else if $style == "blink" { + @include underline_blink($color, $hover); + } +} + +/** Icons */ + +@mixin _inject_icon_style($name, $family) { + display: inline; + color: inherit !important; + background: none !important; + -webkit-mask-image: none !important; + mask-image: none !important; + -moz-user-select: none; + -webkit-user-select: none; + user-select: none; + vertical-align: middle; + font-size: 0.8rem; +} + +@mixin icon_with_name($name, $family, $icon_map, $icon: "", $position: "right") { + @if $icon != "" and map-has-key($icon_map, $icon) { + &::after { + content: map-get($icon_map, $icon); + @if $position == "right" { + margin-left: 0.25rem; + margin-right: 0.1rem; + @include _inject_icon_style($name, $family); + @include font.register-font($name, $family); + @include font.inject-font($family); + } @else if $position == "left" { + margin-left: 0.1rem; + margin-right: 0.25rem; + @include _inject_icon_style($name, $family); + @include font.register-font($name, $family); + @include font.inject-font($family); + } + } + } +} + +@mixin icon-position($name, $family) { + &[data-icon-pos="left"]::before { + margin-left: 0.1rem; + margin-right: 0.25rem; + @include _inject_icon_style($name, $family); + @include font.register-font($name, $family); + @include font.inject-font($family); + } + &[data-icon-pos="right"]::after { + margin-left: 0.25rem; + margin-right: 0.1rem; + @include _inject_icon_style($name, $family); + @include font.register-font($name, $family); + @include font.inject-font($family); + } +} + +@mixin generate-position-map($map: ()) { + @each $key, $value in $map { + &.icon-#{$key}[data-icon-pos="right"]::after { + content: $value; + } + &.icon-#{$key}[data-icon-pos="left"]::before { + content: $value; + } + } +} diff --git a/theme/styles/utils/docs-link.scss b/theme/styles/utils/docs-link.scss index a903822..2f55760 100644 --- a/theme/styles/utils/docs-link.scss +++ b/theme/styles/utils/docs-link.scss @@ -1,5 +1,6 @@ $underline-width: 0.07rem; $underline-padding-bottom: 0.05rem; + @mixin underline-normal { text-decoration: none; // border-bottom: $underline-width solid currentColor; @@ -30,4 +31,4 @@ $underline-padding-bottom: 0.05rem; } padding-bottom: $underline-width + $underline-padding-bottom; background-repeat: no-repeat; -} \ No newline at end of file +} diff --git a/vitepress.config.ts b/vitepress.config.ts index 8ac5acb..cc7fed2 100644 --- a/vitepress.config.ts +++ b/vitepress.config.ts @@ -48,7 +48,8 @@ export default defineConfig({ }, outline: { - label: '本页导航' + label: '本页导航', + level: [2, 3] }, lastUpdated: { @@ -74,6 +75,10 @@ export default defineConfig({ hostname: 'https://ns.openctf.net' }, + markdown: { + math: true, + }, + srcDir: 'docs', outDir: 'dist', assetsDir: 'assets',