这是Crypto方向的笔记
以下大多是主播在网站CryptoHack上做题总结的知识点以及WP
0x01
一个python代码,可以输出flag
#!/usr/bin/env python3
import sys
# import this
ords = [81, 64, 75, 66, 70, 93, 73, 72, 1, 92, 109, 2, 84, 109, 66, 75, 70, 90, 2, 92, 79]
print("Here is your flag:")
print("".join(chr(o ^ 0x32) for o in ords))
import this
下面是逐行讲解
#!/usr/bin/env python3
在linux/mac系统中指明编译器,在windows中会被当成注释而无效。
import sys
导入system模块,其中有许多与系统相关的功能(但是这里好像没有用到)。
ords创建并初始化了一个数组ords,用于存放密文。
print("".join(chr(o ^ 0x32) for o in ords))
这段代码处理并输出了flag。for o in ords代表将ords中的元素存储到了临时变量o中,相当于将ords中的元素依次处理。join()方法可以用于拼接,将解密的文字拼接起来。 chr()函数用于将数字按照ASCII码表转换为对应的字符。经过o ^ 0x32的异或处理后解密为需要的明文,而前面的""是连接符,表示收尾相接,不插入任何东西。
CryptoHack – CryptoHack 简介 - Great Snakes
0x02
十六进制(hex):将十六进制转换为字节bytes.fromhex(),将字节转换为十六进制hex()例如:hes(255)->0x63,以及.hex()例如:b"Hello".hex()→ '48656c6c6f'
同时还可以这么用:
b"crypto{test}".hex(sep=" ", bytes_per_sep=2)
# → '6372 7970 746f 7b74 6573 747d'
可以用于分组,每2个字节一组。
base64:导入库import base64,函数编码base64base64.b64encode()
字节和大整数:导入库from Crypto.Util.number import *,字节转longbytes_to_long, 以及long_to_bytes
异或:XOR 是一个位向算符,如果位相同则返回 0,否则返回 1。在教材中,XOR 算子用 ⊕ 表示,但在大多数挑战和编程语言中,你会看到用 caret 代替。
有关ASCII码:为了将crypto转化为一个ASCII码组成的数组,实现方法:
label = "crypto"
ords = [ord(c) for c in label]
print(ords)
# → [99, 114, 121, 112, 116, 111]
以及:
label = "crypto"
ords = []
for c in label:
ords.append(ord(c))
print(ords)
# → [99, 114, 121, 112, 116, 111]
chr()可以用于将整数转换为ASCII对应的字符
0x03
利用XOR的各个属性(同一律等)进行解密的一道题
题目:
KEY1 = a6c8b6733c9b22de7bc0253266a3867df55acde8635e19c73313
KEY2 ^ KEY1 = 37dcb292030faa90d07eec17e3b1c6d8daf94c35d4c9191a5e1e
KEY2 ^ KEY3 = c1545756687e7573db23aa1c3452a098b71a7fbf0fddddde5fc1
FLAG ^ KEY1 ^ KEY3 ^ KEY2 = 04ee9855208a2cd59091d04767ae47963170d1660df7f56f5faf
使用python实现,下面是我的做法:
from Crypto.Util.number import *
key1=bytes.fromhex("a6c8b6733c9b22de7bc0253266a3867df55acde8635e19c73313")
key1_key2 = bytes.fromhex("37dcb292030faa90d07eec17e3b1c6d8daf94c35d4c9191a5e1e")
key2_key3 = bytes.fromhex("c1545756687e7573db23aa1c3452a098b71a7fbf0fddddde5fc1")
flag_key1_key2_key3=bytes.fromhex("04ee9855208a2cd59091d04767ae47963170d1660df7f56f5faf")
key2 =bytes_to_long(key1)^bytes_to_long(key1_key2)
key3 = key2^bytes_to_long(key2_key3)
flag = long_to_bytes(bytes_to_long(flag_key1_key2_key3)^bytes_to_long(key1)^key2^key3)
print(flag)
及其粗暴,但做出来还是挺有成就感的
下面是网络大蛇的做法:
from pwn import xor
k1=bytes.fromhex('a6c8b6733c9b22de7bc0253266a3867df55acde8635e19c73313')
k2_3=bytes.fromhex('c1545756687e7573db23aa1c3452a098b71a7fbf0fddddde5fc1')
flag=bytes.fromhex('04ee9855208a2cd59091d04767ae47963170d1660df7f56f5faf')
print(xor(k1,k2_3,flag))
哇xor()刚学的就忘,你不用打ctf了
0x04
扩展欧几里得算法
首先是裴蜀定理,定义如下:
$$
pu+qv=gcd(p,q)
$$
是否有解?使用python实现。
首先是一个结论:
$$
gcd(a,b)=gcd(b,a % b )
$$
这意味着可以使用递归实现函数
RSA算法
非对称加密算法
原理:
1.两个大素数p和q,假设两数长度一样
2.计算n=pq
3.计算欧拉函数:
$$
\varphi(n)=(p-1)(q-1)
$$
4.选取加密密钥e,其与phi(n)互质,合适的e可以加快加解密速度.e的常用值有3,17,65537(2^16+1)
5.使用扩展欧几里得算法(辗转相除法)求出e模phi(n)的逆元d,即:
$$
ed \equiv 1 mod \varphi(n)
$$
指路:欧几里得算法
6.m明文,c密文,加密公式为:
$$
c=m^emodn
$$
相应的,解密公式反过来即可。
但是由于数字太大,一般使用快速幂取模,分布计算减小计算量
而python自带的pow()可以自动实现快速幂取模,上式的加密公式也可以写成:
pow(m,e,n)
讲解一下扩展欧几里得算法:
首先是mod符号,意思是"按模......",比如:
$$
a\equiv b (mod m)
$$
读作a与b模m同余,定义为m整除(a-b)
对于上述的
$$
ed \equiv 1 mod \varphi(n)
$$
意为:
(ed-1)能被phi(n)整除,或是ed 和 1 除以 φ(n) 的余数相同
即存在k,使得:
$$
(ed-1)/\varphi(n)=k
$$
$$
k·\varphi(n)=ed-1
$$
顺便附上一个c语言求最大公约数的程序:
#include<stdio.h>
int main(void)
{
int a, b, c;
int temp1,temp2,min,max;
scanf("%d %d %d", &a, &b, &c);// 即min/max
temp1 = a > b ? a : b;
temp2 = a < b ? a : b;
max = temp1 > c ? temp1 : c;
min = temp2 < c ? temp2 : c;
int t;//此处利用 辗转相除法(欧几里得算法) 得到max和min的最大公约数
int m = max;
int n = min;
while (n != 0)
{
t = m % n;
m = n;
n = t;
}
printf("%d/%d", min/m, max/m);
return 0;
}
同时附上一个欧几里得算法的实例(来源于百度百科):
假如需要求 1997 和 615 两个正整数的最大公约数,用欧几里得算法,是这样进行的:
1997 ÷ 615 = 3 (余 152)
615 ÷ 152 = 4(余7)
152 ÷ 7 = 21(余5)
7 ÷ 5 = 1 (余2)
5 ÷ 2 = 2 (余1)
2 ÷ 1 = 2 (余0)
以除数和余数反复做除法运算,当余数为 0 时(即除数可以整除被除数),可得当前中的被除数、除数的最大公约数是除数,根据欧几里得算法原理,就得出了 1997 和 615 的最大公约数 1。
先用大数a除以小数b(算式1),得到的余数作为算式2的除数,而算式1的除数作为算式2的被除数;循环直到余数为0,得到的除数就是最大公约数,也就是gcb(a,b)
0x05
对负数取模:
What is the output when this statement executed: System.out.printf(-7 % 3)
而余数的定义是:
如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = qd+ r 且0 ≤ r < d。其中,q 被称为商,r 被称为余数。
即:$-7=3\times(-3)+2$
因此余数是2
二次剩余
在模 n 的意义下,如果一个整数 a 能写成某个整数的平方,那么 a 就叫模 n 的二次剩余;否则叫二次非剩余。
定义是:设n为正整数,gcd(a,n)=1.如果存在整数x,使得
$$
x^2\equiv,a,(mod,n)
$$
则称a是模n的二次剩余,而x就是a在模n下的平方根
也就是说,二次剩余就是“模某个数下能开平方的数。
这些内容在《初等数论》p195中有提到
Legendre符号
用于判断是否为二次剩余(quadratic residue)
Quadratic Residue * Quadratic Residue = Quadratic Residue
Quadratic Residue * Quadratic Non-residue = Quadratic Non-residue
Quadratic Non-residue * Quadratic Non-residue = Quadratic Residue
如果觉得麻烦,其实可以转换一下:
quadratic residue为1,而quadratic non-residue为-1,同样成立
而legender symbol的主要内容是:
$$
(a/p)\equiv a^{(p-1)/2}mod,p
$$
(a/p)=1 | a is a quadratic residue and a 恒等 0 mod p
(a/p)=-1 | a is a quadratic non-restdue
(a/p)=0 | a 恒等 0 modp
关于Tonelli-Shanks算法_python-CSDN博客
在sympy库中有关二次剩余的函数
is_quad_residue(a,p)#判断是否是二次剩余
quadratic_residues(a)#枚举模p的二次剩余
sqrt_mod(a,p)#求满足 x² ≡ a (mod p) 的整数 x
#其中的第三个参数:all_roots=True 会返回所有原根
nthroot_mod()#见下
nthroot_mod(a, n, p, all_roots=False)
nthroot_mod()用于求解于 $n ^{index}\equiv x\pmod p$的同余式
给定 a, n, p,找出所有满足 xⁿ ≡ a (mod p) 的 x
x\pmod p -> $x\pmod p$
有关线性同余
中国剩余定理
用于求解一组模数互质的同余方程组
在知道一个数除以几个两两互质的数的余数,就可以唯一确定这个数除以他们乘积的余数
例题:

懒人做法直接使用sympy库中的solve_congruence()函数解决:
result=solve_congruence((2, 3), (3, 5), (2, 7)
print(result)