古典加密算法/编码算法
凯撒加密
也叫移位密码
若a–1,b–2,c–3…,则对于明文中任意一个字符$\alpha$,有$\alpha=(\alpha+\beta)%26$,其中$\beta$是密钥
破解方式:穷举密钥,可以配合统计字母频率
仿射密码
quotaed-printable密码
$e(x)=ax+b$,其中$a$和字母数$m$互素
$d(x)=a^{-1}(x-b),a^{-1}a\equiv1\mod m$
凯撒加密升级版
单表代换密码:每一个字符被替换成不同的字符,偏移量不再像凯撒密码一样固定
破解方式:统计字母频率,然后把频率高的替换成实际情况下频率高的
维吉尼亚密码
参考:维吉尼亚密码的原理及破解 - ZCyu的文章 - 知乎
https://zhuanlan.zhihu.com/p/111611977
假设明文为$P=p_1p_2…p_n$,密钥为$K=k_1k_2…k_m$,密文为$C=c_1c_2…c_n$
则$c_i=(p_i+k_{i\mod m})\mod 26\p_i=(c_i-k_{i\mod m})\mod 26$
例子:明文ILOVEMIMAXUE,密钥 AWSL,密文 IHGGEIAXATMP
破解方式
由于维吉尼亚密码每一个字母的加密还与它在明文中的位置有关,所以简单的字母频率分析不起作用
- Kasiski测试
由于密钥循环重复,知道密钥长度m后破解难度就会降低。使用Kasiski测试,将相同的字母组找出来,然后求距离差的最大公约数,猜测m
因为给定长度为m的密钥周期性地加密,当铭文中有两个相同的字母组(长度大于3),在明文序列中相隔字符数为m地倍数时,加密出的密文必定相同。反过来,若密文中出现相同的组合,则对应的明文字母组未必相同,但是相同的可能性极大
- 重合指数法
设一门语言由n个字母组成,每个字母发生的概率为$P_i$,则重合指数指其中两个随机元素相同的概率的和$CI=\sum\limits_{i=1}^nP_i^2$
完全随机的英文文本$CI=26\left(\frac{1}{26}\right)^2=0.0385$,有意义的英文文本$CI=0.065$
实际使用的是$CI$的估计值$CI’$,$L$为密文长度,$f_i$为第$i$个字母发生的次数$CI’=\sum\limits_{i=1}^n\frac{f_i}L\cdot\frac{f_i-1}{L-1}$
如果密文重合指数较低,就是多表代换密码,如果结果接近0.065,则猜测正确
测试m=1,2,3,…
可以把明文分成m个一组,假设密钥长度为m,则每组的相同位置的密钥相同,可以基于这个特点检测重合指数,判断密钥长度
- Chi测试(应该是卡方检验吧,测试统计样本和理论值的偏移程度)
用于确定密钥内容
某种语言由$n$个字母组成,$p_i$为字母$i$在维吉尼亚密文分布中发生的概率$q_i$表示在正常英文文本中发生的概率,拟重合指数定义为
$\chi=\sum\limits_{i=1}^np_iq_i$
对于一个移位密码
- 统计每个字母的频数$f_0,f_1,…,f_{26}$
- 令密文长度为$n’=\frac{n}m$,则字母的频率分布$p_i=\frac{f_i}{n’}$
- 通常文本概率分布$q_0,q_1,…,q_{26}$
- 对于每一列进行移位,得到每一位对应的偏移量i,得到$P_i=p_{26-i},…,p_{25},p_0,p_1,…,p_{25-i}$
- 对分布$P_i$和$Q$进行相关卷积计算$C(P_i,Q)=\sum\limits_{j=0}^26P_{(i+j)\mod 26\cdot q_j}$
- 得到最大相关值即为偏移量的估计值
相关数论基础
辗转相除法
用于计算两个数的最大公约数,也叫欧几里得法
$gcd(a,b)=gcd(b,a\ mod\ b),a,b\in Z$
直到
$a%b=0$
此时$b$就是最大公约数
证明过程待后续
代码实现
1 | uint32_t gcd(int32_t a,int32_t b){ |
快速幂
用于快速计算$a^n,n\in N,a\in Z$
$$
a^n=\begin{cases}
a^{n-1}\cdot a,n\ is\ odd
\a^{\frac{n}{2}}\cdot a^{\frac{n}{2}},n\ is\ even
\end{cases}
$$
代码实现
1 | int32_t qpow(int32_t a,uint32_t n){ |
中国剩余定理
给出以下的一元线性同余方程组
$$
S:\begin{cases}
x\equiv a_1(mod\ m_1)\
x\equiv a_2(mod\ m_2)\
\ \ \ \ \vdots\
x\equiv a_n(mod\ m_n)
\end{cases}
$$
中国剩余定理给出了有解的判定条件和解的具体形式
若$m_1,m_2,…,m_n$中任两数互质,则对任意整数$a_1,a_2,…,a_n$,方程组$S$有解,通解通过如下方式得到
$M\prod\limits_{i=1}^{n}m_i,M_i=M/m_i,\forall i\in{1,2,…,n}$
$t_i=M_i^{-1}(mod\ m_i)$
$x\equiv \sum\limits_{i=1}^{n}a_it_iM_i(mod\ M)$
证明
由假设,$gcd(M_i,m_i)=1$,则$M_i^{-1}(mod\ m_i)$存在。
考察$x\ mod\ m_i,\because\forall j\ne i,M_j\equiv 0(mod\ m_i)$,从而得到$x\equiv a_it_iM_i(mod\ m_i)$
而$t_iM_i\equiv1(mod\ m_i)$,从而$x\equiv a_i(mod\ m_i)$
唯一性:
设$x_1,x_2$都是$S$的解,则$\forall i\in{1,2,…,n},x_1-x_2\equiv 0(mod\ m_i)$
而$gcd(m_i,m_j)=1,i\ne j,i,j\in{1,2,…,n}$,从而由$x_1-x_2\equiv0(mod\ M)$,从而说明是$x_1=x_2$
费马小定理
$a^{p-1}\equiv 1(mod\ p),p$是质数且$a\ne0(mod\ p)$
hash算法
md5
- 填充
在消息后面先填充一个1,再填充0,直到消息长度mod 512=448,之后再将消息长度的低64位填充到消息结尾
- 定义几个运算
F(x,y,z)=(x&y)|(~x&z)
G(x,y,z)=(x&z)|(y&~z)
H(x,y,z)=x^y^z
I(x,y,z)=y^(x|~z)
ROL32(x,i) 左移32位
填充后的消息以512为一个分组,每个分组可以分成16个32位子分组$W_j(0<j<15)$
FF(a,b,c,d,M_j,s,t_i): a=b+ROL32(a+(F(b,c,d)+M_j+t_i),s)
GG(a,b,c,d,M_j,s,t_i): a=b+ROL32(a+(G(b,c,d)+M_j+t_i),s)
HH(a,b,c,d,M_j,s,t_i): a=b+ROL32(a+(H(b,c,d)+M_j+t_i),s)
II(a,b,c,d,M_j,s,t_i): a=b+ROL32(a+(I(b,c,d)+M_j+t_i),s)
- 定义初始化向量
A=0x01234567
B=0x89abcdef
C=0xfedcba98
D=0x76543210
- 对于每一个分组,将上一次计算的A,B,C,D复制到a,b,c,d中,进行下面的4轮计算,然后将a,b,c,d分别加到A,B,C,D上,下一组继续运行此算法,最终输出就是A||B||C||D,||在这里代表拼接
1 | # 第一轮 |
其中pos和t,s数组会在代码中体现
1 |
|
参考资料
《应用密码学:协议、算法与C源程序》
对称加密算法
加密模式
设$c_i,p_i,iv,f$分别为第$i$个密文块,明文块,初始向量,加密函数。ECB模式无$iv$。
ECB
每个块自行加密
$c_0=f(p_0),c_1=f(p_1),…,c_n=f(p_n)$
CBC
当前块加密会影响到以后的块
$c_0=f(iv\oplus p_0),c_1=f(p_1\oplus c_0),…,c_n=f(c_{n-1}\oplus p_n)$
AES
参考自https://ctf-wiki.github.io/ctf-wiki/crypto/blockcipher/aes-zh/
https://bbs.pediy.com/thread-253884.htm#msg_header_h1_0
也叫Rijndael 128加密法。加密过程中,每一块都是128比特。
使用代换-置换网络
加密的单位为4*4字节共4步
AddRountKey
每一回合与该次密钥做xor运算,密钥通过Rijndael密钥生成方案产生
SubBytes
把每一个字节通过查找表(s盒)的方式替换成另一个
ShiftRows
可以理解为每个双字单位分散到其它双字
这里是不同双字的混合
MixColumns
使用线性变换在一个双字内部混合
这里是一个双字内部的混合
实现中表现为一个矩阵乘
第一轮加密之前需要进行“白化操作”,即首先异或密钥
最后一轮没有MixColumns操作,使用AddRountKey替代
1 |
|
特点
S盒,密钥生成中的常量
参考资料:[AES–wikipedia](高级加密标准 - 维基百科,自由的百科全书)
DES
Fiestel网络
16个相同的过程,块长度为64位,分成两个32位的半块v1,v2
总体过程:
进行一次置换,称为IP
进行16轮如下操作
s1=v1^F(v2)
v1=v2
v2=s1
其中F为Fiestel函数,包含扩张,与密钥混合,S盒,置换操作
进行一次置换,成为FP,FP为IP的逆函数
IP和FP是简化输入输出数据库的过程而被显式地包含在标准中
Fiestel函数
扩张
将32为半块扩展到48位,包含8个6位块,每块包含4位输出位,加上邻接块中紧邻的位
与密钥混合
用异或操作将扩张结果和子密钥混合,子密钥是通过密钥调度产生的
S盒
与子密钥混合后,分成6个8位的块,然后使用S盒置换处理
置换
32个输出位利用P置换进行重组
特点
S盒
参考资料:DES–wikipedia
tea
可以加密两个无符号整数
参考代码(来自wikipedia)
1 |
|
也有部分变种,大多是变了delta,或者delta使用v0=(0-(-delta))
xtea
参考代码(来自wikipedia)
1 |
|
相比tea,在使用密钥更不确定,特征值不变
xxtea
参考代码(来自wikipedia)
1 |
|
n表示v的长度,正数表示加密,负数解密
SM4
密钥长度为128bits
加密算法和密钥扩展算法都是32位非线性迭代结构
加解密算法结构相同,轮密钥的使用顺序相反
定义运算
32位数$x$向左循环移动$i$位$:x<<<i,\oplus$为异或
1 |
定义参量
密钥长度位128bits $MK=(MK_0,MK_1,MK_2,MK_3)$
轮密钥为32*32bits $rk=(rk_0,rk_1,…,rk_{31})$
$FK=(FK_0,FK_1,…,FK_3)$为系统参数,$CK=(CK_0,CK_1,…,CK_{31})$为固定参数
$CK_{i,j}=(4i+j)*7\ mod\ 256$,其中$i$为双字编号,$j$为字节编号,$j$采用大端序
1 |
|
轮函数F
$F(X_0,X_1,X_2,X_3,rk)=X_0\oplus T(X_1\oplus X_2\oplus X_3\oplus rk)$
合成置换$T(.)=L(\tau(.))$
若输入为$A=(a_0,a_1,a_2,a_3)$,其中$a_i$为8字节无符号整数,则非线性置换$\tau(A)=(sbox[a_0],sbox[a_1],sbox[a_2],sbox[a_3])$
$sbox$为替换用s盒
若输入为$B$,其中$B$为32字节无符号整数,则线性变换$L(B)=B\oplus (B<<<2)\oplus(B<<<10)\oplus(B<<<18)\oplus(B<<<24)$
1 |
|
加密算法
反序变换$R(a_0,a_1,a_2,a_3)=(a_3,a_2,a_1,a_0),a_i$为8位
设输入为$(X_0,X_1,X_2,X_3),X_i$为32位
输出为$(Y_0,Y_1,Y_2,Y_3)$
则$X_{i+4}=F(X_i,X_{i+1},X_{i+2},X_{i+3},rk_i)$
$(Y_0,Y_1,Y_2,Y_3)=R(X_{32},X_{33},X_{34},X_{35})$
解密过程和加密过程变换结构相同,不同的是轮密钥顺序
加密时$(rk_0,rk_1,…,rk_{31})$
解密时$rk_{31},rk_{30},…,rk_0$
1 | void crypt(uint32_t p[4],uint32_t crk[31]){ |
密钥扩展算法
密钥$MK=(MK_0,MK_1,MK_2,MK_3)$
$K=(K_0,K_1,…,K_{31})$
$(K_0,K_1,K_2,K_3)=(MK_0\oplus FK_0,MK_1\oplus FK_1,MK_2\oplus FK_2,MK_3\oplus FK_3)$
轮密钥为$rk,rk_i=K_{i+4}=K_i\oplus T’(K_{i+1}\oplus K_{i+2}\oplus K_{i+3}\oplus CK_i)$
$T’$和$T$基本相同,其中的$L’=B\oplus(B<<<13)\oplus(B<<<23)$
1 |
|
完整代码
1 |
|
参考资料
[1] SM4算法标准
公钥加密算法
rsa
费马小定理
$p$是质数,$a$不是$p$的倍数,$a^{p-1}mod\ p\equiv1$
那么对于数据$a$,加密后的数据为$c$,私钥为$e,p,q$,公钥为$d,n$
其中$n=pq$,$ed\equiv 1(\mod (p-1)(q-1))$
则加密
$$
c=a^{e}\mod n
$$
解密
$$
c^{d}\mod n\equiv (a^e)^d\mod n\equiv a^{ed}\mod n
$$
由于
$$
a^{ed}\equiv a^{1+t(p-1)(q-1)}\mod n=aa^{(p-1)(q-1)}\mod n
$$
又由于$n=pq,ab\mod n=(a\mod n)(b\mod n)\mod n$
得到
$$
a^{(p-1)(q-1)}\mod n
$$
从而
$$
(a^{p-1})^{q-1}\mod pq\equiv a^{p-1}\mod p\equiv 1
$$
从而解密出来为$a$
攻击方式
共模攻击
$c_1=a^{e_1}\mod n,c_2=a^{e_2}\mod n,gcd(e1,e2)=1$
则有辗转相除法有$xe_1+ye_2=1$
则$c_1^{x}+c_2{y}=a^{xe_1+ye_2}=a$
ElGamal
// TODO
其它加密算法
CRC32
用于校验数据
1 | uint32_t CRC(uint32_t *v,size_t len){ |
CRC并不安全,只用于传输过程中完整性的校验
base系列
base64,base56,base32,base16
找到base表
差分密码分析
攻击者选取一部分明文并获取相应密文,运用若干对有着常量差异的明文,计算其中的差异$\Delta x=f(x_1,x_2)$,其中$f$可以自定义,比如异或操作。
然后攻击者计算相应密文的差异,尝试找出差异分布的统计特征。明文差异和密文差异所组成的差异叫做差分,统计特征由所使用的S盒所决定。
对于S盒$S$,攻击者分析差分$(\Delta x,\Delta y),\Delta y=S(x\oplus \Delta x)\oplus S(x)$。攻击者希望某个密文差异出现的频率非常高,这样就能将加密和随机过程区分开来。
最基本的差分密码分析密钥破解形式中,攻击者首先获取大量明文对的密文,并假设差分在至少r − 1轮后有效,r即加密算法的总轮数。攻击者在倒数第二轮与最后一轮之间差异固定的假设下,去推测可能的轮密钥。如果轮密钥比较短,那么只需举可能的轮密钥,直到最后一轮运算结果和差异的密文对一致即可。当一个轮密钥看起来明显比其他密钥常出现时,其会被假设是正确的轮密钥
还不是很懂,回头看英文版似乎有个简单的例子。
参考资料
[1] 差分密码分析–wikipedia
Kerberos认证流程
Kerberos用于服务器认证用户身份
Kerberos保存有所有人的密钥
过程
- 客户从Kerberos认证服务器请求一张票据,该票据用用户的密钥加密之后发送给用户。这个票据是TGS(票据许可服务)
- 客再从TGS请求一张票据,TGS将票据返回给用户
- 用户将此票据呈现给服务器,如果用户身份没问题,服务器便会提供服务