CRYPTO中的XOR问题

XOR是CTFer在做题中常见的问题,本文分享一下我在做题过程中遇到的经典问题

什么是XOR

XOR即”异或运算“,它在数学表达式中常常写作’’⊕’’,在常见的几种编程语言中,则是用符号’’^’’来表示。

XOR运算遵循这样的规则:

1⊕1 = 0

0⊕0 = 0

1⊕0 = 1

0⊕1 = 1

在实际运算中,它是按位运算的。现有二进制10010和11001,二者异或的结果为01011。

XOR的运算性质

XOR运算具有

1)交换律

2)结合律

3)归零律:A⊕A=0

4)恒等律:A⊕0=A

由其归零率和恒等率我们还可以推出:

A⊕B=C

即A⊕B⊕B=C⊕B

即A=C⊕B

这就说明了为什么单单使用XOR,属于对称密码。假设A是密文,B是密钥,经过上面的步骤可以看出只要知道密钥B,就能将密文和明文相互转化。

XOR题型举例

利用运算性质

本题来源于cryptohack

1
2
3
4
KEY1 = a6c8b6733c9b22de7bc0253266a3867df55acde8635e19c73313
KEY2 ^ KEY1 = 37dcb292030faa90d07eec17e3b1c6d8daf94c35d4c9191a5e1e
KEY2 ^ KEY3 = c1545756687e7573db23aa1c3452a098b71a7fbf0fddddde5fc1
FLAG ^ KEY1 ^ KEY3 ^ KEY2 = 04ee9855208a2cd59091d04767ae47963170d1660df7f56f5faf

求FLAG只需让4式异或1式和3式

python实现如下:

1
2
3
4
5
6
7
8
from pwn import *
KEY1 = bytes.fromhex('a6c8b6733c9b22de7bc0253266a3867df55acde8635e19c73313')
KEY2_KEY1 = bytes.fromhex('37dcb292030faa90d07eec17e3b1c6d8daf94c35d4c9191a5e1e')
KEY2_KEY3 = bytes.fromhex('c1545756687e7573db23aa1c3452a098b71a7fbf0fddddde5fc1')
FLAG_KEY1_KEY3_KEY2 = bytes.fromhex('04ee9855208a2cd59091d04767ae47963170d1660df7f56f5faf')
step1 = xor(FLAG_KEY1_KEY3_KEY2,KEY1)
step2 = xor(step1,KEY2_KEY3)
print(step2)

注:1. 使用了pwntools库中的xor()函数

​ 2.bytes.fromhex()函数的作用是将十六进制字符组成的字符串转化为字节序列,即’a6c8b6’转化为0xa6 0xc8 0xb6的序列

碰撞已知的明文片段

image-20250204192002493

本题我们已知密钥仅为一个字节,又知道最终flag为crypto{xxxxxx}的形式

根据XOR运算的性质,我们只需要让密文首个字节与字母’c’异或,就能得到密钥

python实现:

1
2
3
4
5
6
7
from pwn import *
m = '73626960647f6b206821204f21254f7d694f7624662065622127234f726927756d'
m_bytes = bytes.fromhex(m)
key = xor(0x73,'c')
print(key)
p = xor(m_bytes,key)
print(p)

对图片的XOR

基本原理:图片由许多像素点排列组成,我们可以把每个像素点的灰度或RGB(red,green,blue,可以认为每个像素点的颜色是由这三种颜色不同比例混合而成的)的数值当作异或的对象。将异或得到的数值再转化为灰度或RGB,形成新的图片。

常用的工具:python的PIL库

例题来自cryptohack,感兴趣可自行查看

image-20250204193936704

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from PIL import Image
image1 = Image.open("F:\pythonscript\cryptohack\Lemur_XOR\lemur_ed66878c338e662d3473f0d98eedbd0d.png")
image2 = Image.open("F:\pythonscript\cryptohack\Lemur_XOR\\flag_7ae18c704272532658c10b5faad06d74.png")

#生成可操作的对象,pim类似于矩阵,通过坐标值来操控每个像素
pim1 = image1.load()
pim2 = image2.load()

width,height=image1.size

for i in range(width):
for j in range(height):
r1,g1,b1 = pim1[i,j]
r2,g2,b2 = pim2[i,j]
pim1[i,j] = (r1^r2, g1^g2, b1^b2)

image1.show()

注:Image.open()函数即打开图片文件

​ .load()函数生成一个矩阵,通过坐标值来访问图片中的每个像素

​ .size能分别得出图片的宽和高(像素点个数)

​ r1,g1,b1 = pim1[i,j]这一句是得到[i,j]位置处的RGB值

​ .show()函数负责弹窗展示图片

感觉这一题更像是misc会出的东西。