[TOC]
HNCTF
baBAbaseSEse(base家族)
base家族
babyRsa(基本RSA)
基础知识
注意:这里不能安装其他库,不然会因为版本问产生一系列的兼容性问题
- PyCryptodome库主要由以下模块组成:
Crypto.Cipher
:包含对称加密算法,如AES、DES等。Crypto.PublicKey
:包含非对称加密算法,如RSA、DSA等。Crypto.Hash
:包含哈希函数,如SHA256、MD5等。Crypto.Signature
:包含数字签名相关功能。Crypto.Random
:提供随机数生成器。Crypto.Protocol
:包含各种协议实现,如PBKDF2。Crypto.Util
:包含一些实用工具,如填充、字节处理等
对于RSA的一些工具
YAFU: YAFU(Yet Another Factoring Utility)是一个开源的用于整数因数分解的命令行工具。它是一个强大而灵活的工具,能够分解大整数为其质因数,有助于解决数论和密码学领域中的问题。YAFU是基于GMP(GNU多精度算法库)的,并使用了多种因数分解算法来优化分解过程。它是数学爱好者、密码学研究人员和密码分析者常用的工具之一
1
2
31.使用 cmd 进入到 yafu 所在目录下,或将目录加入到系统环境 PATH 变量,或打开目录文件夹后 shift+右键 选择在此处打开 powershell
2.假如要分解因数 6 ,输入命令:.\yafu-x64.exe "factor(6)"
3.如果因数过长,将 因数 用文本文件存放在 yafu 目录下,例如:data.txt 。文件最后一行一定要换行,否则eof; done processing batchfile。 运行命令:.\yafu-x64.exe "factor(@)" -batchfile data.txtFactorDB: FactorDB是一个在线的整数因数分解数据库。它允许用户将大整数提交到数据库,并查找其质因数分解。这个数据库是由全球用户提交的整数分解结果共同维护的,它采用了多种现代算法来分解整数。FactorDB 对于那些没有自己的因数分解工具或想要验证分解结果的用户来说是非常有用的。通过FactorDB,用户可以快速地找到一个整数的质因数,而无需自行进行因数分解运算 网站factordb.com
这个题是一个简单的RSA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17from Crypto.Util.number import bytes_to_long, getPrime
# 这里我们导入了bytes_to_long函数,它用于将字节转换为长整数(将flag转换为m),以及导入了getPrime函数,它用于生成指定位数的随机素数。
from gmpy2 import *
P39 = 265147241000574873803071047177766359643
P39 = 234560843346150602519484260867514743467
q = getPrime(128)
p = getPrime(128)
# 这两行代码使用getPrime(128)函数生成两个128位的随机素数,并将它们赋值给变量p和q。在RSA加密中,p 和 q 是用于计算 RSA 公钥和私钥的重要参数。
n = p * q
e = 65537
c = 17331436837911040930486942133359735652484926528331507431552667656734821231501
# n 是RSA的模数,它是两个素数 p 和 q 的乘积。
# e 是RSA的公钥指数,通常为固定值 65537(也称为常用的 RSA 公钥指数)。
# c 是RSA的密文,通过用公钥指数 e 对明文 m 进行模幂运算得到。
print(n,c)
# 62193160459999883112594854240161159254035770172137079047232757011759606702281
# 17331436837911040930486942133359735652484926528331507431552667656734821231501通过上述工具进行分解之后,然后写出对应的解密脚本即可,这里主要是了解了这些库的一些基本使用而已
1
2
3
4
5
6
7
8
9
10
11
12
13计算 RSA 私钥参数:
使用已知的 p 和 q 计算了模数 n,并通过调用 invert(e, (p-1)*(q-1)) 函数计算得到私钥指数 d。
RSA 解密并输出明文:
使用得到的私钥指数 d 和模数 n,将密文 c 进行 RSA 解密,并通过 long_to_bytes 函数将解密后的长整数转换为明文,并进行输出。
from Crypto.Util.number import bytes_to_long, getPrime, long_to_bytes
from gmpy2 import *
e = 65537
p = 234560843346150602519484260867514743467
q = 265147241000574873803071047177766359643
c = 17331436837911040930486942133359735652484926528331507431552667656734821231501
n = p * q
d = invert(e,(p-1)*(q-1))
print(long_to_bytes(pow(c,d,n)))然后安装了sage的软件,还没有使用,明天再看看吧!
A dictator(凯撒密码)
凯撒密码就是根据偏移移位的密码
加密过程
1 | from random import randint |
解密过程:这个加密解密完都是小写字母,通过25个随机数字进行爆破解密即可
1 | cipher = 'nby_wuymul_wcjbyl_cm_ihy_iz_nby_gimn_vumcw_wfummcwuf_wcjbylm' |
官方wp有一个string的库,这里学习了一下
问:from string import ascii_lowercase string库是什么库?
答:在Python中,
string
是一个标准库,它包含了许多与字符串处理相关的常用常量和函数。通过导入string
库,你可以使用其中定义的常量和函数,而不需要自己定义相同的内容。在给定的代码中,使用
from string import ascii_lowercase
导入了string
标准库中的ascii_lowercase
常量。ascii_lowercase
是一个包含所有小写字母的字符串,它的值为'abcdefghijklmnopqrstuvwxyz'
。这样一来,代码就可以直接使用ascii_lowercase
变量来表示小写字母表,而不需要手动定义这个字符串。
爱妃(仿射密码)
放射密码(Affine Cipher)是一种古典密码学中的替换密码,它对字母表中的字符进行加密和解密。放射密码的数学原理涉及到仿射函数的应用。
放射函数的一般形式为:E(x) = (ax + b) mod m
其中:
- E(x) 表示密文字符;
- x 表示明文字符;
- a 和 b 是整数,并且满足 a 和 m 互质(最大公约数为1);
- mod m 表示对 m 取模,即结果在 0 到 (m-1) 的范围内。
在放射密码中,每个明文字符 x 被映射为一个密文字符 E(x)。参数 a 和 b 是放射函数的密钥,通过正确选择这些密钥,可以实现有效的加密和解密。
解密过程是对密文字符应用逆放射函数:D(y) = a^(-1) * (y - b) mod m,其中 a^(-1) 表示 a 的乘法逆元素。
1 | import gmpy2 |
littleprince(同余方程,中国剩余定理)
这道题的给的加密代码有一些难理解,在这里记录一下
1 | from secret import flag |
掩码
在计算机科学中,”掩码”(Mask)是一个用于屏蔽或提取某些位的二进制模式。掩码通常是一个与目标数据进行按位与操作的值,通过这种操作,可以将目标数据的某些位设置为0或从中提取出感兴趣的位。
掩码在计算机编程和计算机系统中有广泛的应用,主要用于以下两个方面:
- 屏蔽位:掩码可以用于屏蔽目标数据的特定位。通过将目标数据与相应的掩码进行按位与操作,可以将不需要的位设置为0,而保留需要的位。这在编程中常用于清除或保留特定标志位,或者过滤掉数据中不需要的部分。
- 提取位:掩码还可以用于从目标数据中提取出感兴趣的位。通过将目标数据与相应的掩码进行按位与操作,可以将目标数据的其他位设置为0,而保留感兴趣的位。这在计算机系统中常用于从寄存器或数据中提取出特定字段或标志位。
掩码通常使用二进制形式表示,并且每个位都对应于目标数据的相应位。在掩码中,1 表示需要保留或提取的位,0 表示需要屏蔽的位。
例如,对于目标数据
11010110
,如果我们希望屏蔽掉低三位,我们可以使用掩码11111000
,通过进行按位与操作,结果将是11010000
。同样,如果我们希望提取低四位,我们可以使用掩码00001111
,通过进行按位与操作,结果将是00000110
。
- 总结:与运算取出感兴趣的位,感兴趣为1,不感兴趣为0
关于移位
a >> b | (a & ((1 << b)-1)) << (c-b)
假设
a
等于 87 (二进制:0b1010111
),b
等于 4。
1 << b
的结果为0b10000
,也就是十进制数 16。((1 << b) - 1)
的结果为0b1111
,也就是十进制数 15。a & ((1 << b) - 1)
就是0b1010111 & 0b1111
,结果为0b111
,也就是十进制数 7。所以,
(a & ((1 << b) - 1))
表达式的结果就是a
的低b
位的掩码,它将保留a
二进制表示中的最后b
位,并将其他位设置为0。
RSA系列
RSA原理
生成数字
加密与解密
RSA Py代码实现
Python代码的计算过程
导入子库生成两个大素数,512bit朝
1
2
3
4
5
6from Crypto.Util.number import *
# getPrime函数,它能够返回一个n位的素数
p = getPrime(512)
q = getPrime(512)
print(p)
print(q)计算欧拉函数和n
1
2n = p*q
phi = (p-1)*(q-1)选取e判断互素性,并且计算逆元
1
2
3e = 65537
assert GCD(e, phi) == 1, "该e不满足互素条件"
d = inverse(e, phi)加密hello
1
2
3
4
5
6
7
8
9
10
11# 这里定义的是byte类型的字符串,每个字符用8位的二进制进行存储,如果直接定义字符串hello,字符串类型需要进行编码字节类型才可以进行加密
message = b'hello'
# 使用的bytes_to_long函数,将字符串转换为数字
m = bytes_to_long(message)
print(m)
# 消息已经被转换为一个字符串了,可以加密
c = pow(m, e, n)
print(c)
# 解密
msg = pow(c, d, n)
print(msg)完整代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24from Crypto.Util.number import *
p = getPrime(512)
q = getPrime(512)
n = p*q
phi = (p-1)*(q-1)
e = 65537
assert GCD(e, phi) == 1, "该e不满足互素条件"
d = inverse(e, phi)
print(f'公钥:({e}, {n})')
print(f'私钥:({d}, {n})')
message = b'hello'
m = bytes_to_long(message)
print('消息:', m)
c = pow(m, e, n)
print('密文:', c)
msg = pow(c, d, n)
print('明文:', msg)
assert msg == m, "解密失败"
RSA类型
p-q过小差值小类型
题目代码
1 | from Crypto.Util.number import * |
这里一个特征就是,p通过函数生成512位的素数,然后q为其相邻的下一个素数,可以进行测试
1 | from Crypto.Util.number import * |
解题原理
代码
1 | from Crypto.Util.number import * |
费马分解
对称密码系列
定义:对称加密,称为对称密码,是指在加密和解密时使用同一密钥得加密方式。
特点:比非对称加密要快
DES
典型的块加密,将明文分块加密
特点
在DES中,具有如下特点
- 输入
64
位 - 输出
64
位 - 密钥
64
位,使用64
位密钥中的56
位,剩余的8
位要么丢弃,要么作为奇偶校验位 - 采用Feistel迭代结构:
- 明文经过 16 轮迭代得到密文
- 密文经过类似的 16 轮迭代得到明文
加密过程
初始IP置换
- 64位明文分组X经过一个初始置换函数
IP
,产生64位的输出X0,再将分组X0分成左半部分L0和右半部分R0。- 将输入的第58位换到第一位,第50位换到第2位,…,依次类推。
- L0、R0则是换位输出后的两部分, L0是输出的左32位, R0是右32位。
- 简而言之,这就是打乱了明文之间的排列,我们使用Python来实现这个函数,在这里及后续的代码中,我们都将明文认为是一个数字数组进行操作。
获取子密钥
- 在进入第一轮之前,我们还需要对密钥进行处理生成子密钥,每一轮将使用不同的子密钥参与运算。DES加密算法的密钥长度为56位,一般表示为
64
位(每个第8
位用于奇偶校验),将用户提供的64
位初始密钥经过一系列的处理得到K1,K2,…,K16,分别作为1~16轮运算的16个子密钥。
密码函数F
密码函数F的作用是将输入的32比特数据和48比特子密钥进行加密输出32比特
代码实现
1 | from operator import add |
封装库实现
1 | from Crypto.Cipher import DES |
AES
特点
- 输入:128 比特。
- 输出:128 比特。
- SPN 网络结构。
与DES的注意点
- 每一刻从64位变成128位
- AES采用的的SPN网络结构与Feistel相比,可以加密整个块,并且解密必须是对加密的逆运算
- SPN全称为
Substitution-permutation network
即代换-置换网络,简单的说就是会对块进行替换,置换等多重迭代操作。
迭代过程
- AddRoundKey轮密钥加
- SubBytes字节替换
这里引入一个S盒,然后进行S盒替换 - ShiftRows行位移变换
这也是一次扩散处理,达到雪崩效应(雪崩效应是指当输入发生最微小的改变(例如,反转一个二进制位)时,也会导致输出的不可区分性改变,即扩大错误防止攻击者找到不同明密文之间的关系)。 - MixColumns列混合变换
也是扩散操作 - 子密钥生成
代码实现
1 | r_con = (0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,0x80, 0x1B, 0x36) |
封装库实现
1 | key = b'1234567812345678' |
P1 DES 解密
知识点:DES的F函数可逆,改变一点就可以
无需关注F函数实现,查看16轮迭代
1
2
3
4
5
6L, R = block[:32], block[32:]
for i in range(16):
tpR = R[:]
R = F(i, R, skeys)
R = list(map(lambda x, y: x ^ y, R, L))
L = tpR代码实现,将代码逆过来即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19```
1. 先IP置换函数
2. 十六轮逆过程
3. FP置换函数
```
# 加密代码
L, R = block[:32], block[32:]
for i in range(16):
tpR = R[:]
R = F(i, R, skeys)
R = list(map(lambda x, y: x ^ y, R, L))
L = tpR
# 解密代码
L, R = block[:32], block[32:]
for i in range(15, -1, -1):
tpR = R[:]
R = F(i, R, skeys)
R = list(map(lambda x, y: x ^ y, R, L))
tpR = L
P2 DES 无密钥
1 | def F(index: int, R: List[int], skeys: List[List[int]]): |
P3 DES 密钥爆破
给出L和R和C R缺8位 爆破
1 | L = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1] |
1 | for i in range(2**8): |
P4 DES Kn泄露
1 | import pyDes |
P4 DES Kn泄露 子密钥算法逆向
1 | import pyDes |