加密的语法由三个算法组成:密钥产生,加密,解密
(1) 密钥产生算法Gen是一个概率算法,能够根据方案定义的某种分布方案分布选择并输出一个密钥k
(2) 加密算法Enc,输入为密钥k和明文m,输出为密文c。把使用密钥k加密明文m记为Enck(m) (Encryption)
(3)解密算法Dec,输入为密钥k和密文c,输出为明文m。把使用密钥k解密密文记为Deck(c) (Decryption)
用左箭头表示即使在同一组输入上运行两次,算法的输出也可能不同,
eg:,表示加密可能是随机的,同一组数据分别加密两次得到的密文也可能不同
用:=表示结果是确定性的
eg: m:=Deck(c),表示密文c通过密钥k可以得到唯一的一个结果
对任意加密方案的基本要求是:对于任何通过Gen输出的密钥k,每个明文消息,满足
Deck(Enck(m))=m
Kerckhoffs原则:加密算法应该公开
攻击场景:
mod 表示取余数,下图中第一个式子表明25%10与35%10具有相同的余数,第三个式子表明5等于35%10的结果
为了保证安全,必须有一个足够大的密钥空间防止暴力穷举搜索攻击。但足够大的密钥空间只是必要条件而非充分条件,不能保证方案是安全的
文中介绍了单字母替换,即每个明文字符映射到一个不同的密文字符,其中这种方法可以被英文文本中的字母平均概率猜测映射关系而攻破,但需要查看哪个明文结果是有意义的
书中先利用图1.2算出
#include<bits/stdc++.h>
using namespace std;
int main()
{
double a[26];
double sum=0;
a[0]=0.082;
a[1]=0.015;
a[2]=0.028;
a[3]=0.042;
a[4]=0.127;
a[5]=0.022;
a[6]=0.02;
a[7]=0.061;
a[8]=0.001;
a[9]=0.008;
a[10]=0.04;
a[11]=0.024;
a[12]=0.067;
a[13]=0.075;
a[14]=0.019;
a[15]=0.001;
a[16]=0.06;
a[17]=0.063;
a[18]=0.09;
a[19]=0.028;
a[20]=0.01;
a[21]=0.024;
a[22]=0.02;
a[23]=0.001;
a[24]=0.001;
a[25]=0.07;
for(int i=0;i<26;i++)
{
sum=sum+a[i]*a[i];
}
cout<<sum;//结果为0.065379
}
解释:对于每个i,他移位后的位置记作i+k(用来代替取余数运算),如果猜测得出的位置i+j与i+k相同,此时在密文中得出的频率q(i+j)应与pi相近,此时求出的j即为可能的偏移量。根据式1.1,同时按照上图所计算的式子,若Ij≈0.065,则可能是一组key值
Vigenere加密:
解释:假设密钥的长度为t,则密文可以被分为t个部分,每一个部分中相同位置的偏移量都是一致的。把他们拿出来利用概率制表,他们仍符合图1.2,同样可以利用式
计算t次即可算出密钥
那么如何来确定密钥的长度呢?Kasiski的方法为,第一步发现密文中长度为2或3的重复模式,这些可能是某种英文中出现频繁的2字词或3字词,如"the",所有这种距离的最大公约数即为周期t或t的倍数
如文中的例子:
文中也提到了一种巧合指数方法:
解释:
假设密文为 abcde fghij klmno(只是举个例子,实际所需密文长度应足够长)
猜测密钥长度为5,则拿出a,f,k,算出各个字母出现的长度,带入上图公式,(这里解释一下,他们虽然偏移过算出的概率不是明文中字母对应的概率,但是由于每个字母都偏移过,整体也符合这个规律)
接着拿出b,g,l,继续算出Sr,最终得到几组结果的平均值,如果猜测正确则结果应在0.0065左右,若猜测错误则会以等概率出现,Sr的值约为0.038,此时可以进行新的密钥长度假设并重复此过程
现代密码学的基本原则:
对称密钥加密方案的安全定义:如果没有敌手能够从密文中计算任何关于明文的函数,则加密方案是安全的。这里还需要讨论攻击模型问题,以及应当如何通过数学语言定义