[Stanford Cryptography I] Week1

纠结了一阵子,还是打算啃一啃这门课,不过能啃到哪里我就不清楚了。另外,还是要不时做点笔记什么的。

基本概念:

K:所有可能的密钥(密钥空间)

M:所有可能的明文

C:所有可能的密文

E:加密算法

D:解密算法

因此可以得到: 

E(k, m)=c  密钥和明文通过加密算法得到密文

D(k, c)=m  密钥和密文通过加密算法得到明文

对所有 的明文m,密钥k,D(k, E(k, m))=m  即明文通过一个密钥加密之后再经过同一个密钥解密得到的应该和明文完全相同。


当然,有个条件,你不能加密或者解密用了一辈子时间还算不出来,这样这个加密、解密算法就没有任何意义了。

也就是说,我们的加密解密算法要有效率的。

有效率意味着,时间复杂度是一个多项式的复杂度,或者实际应用中,可以定义例如对于1GB的数据我只需要1分钟即可算出来。

而一般加密算法都是随机的,也就是会随机一个密钥然后再进行加密,但是,解密算法就不能是随机的,也就是说对于给定的密钥和密文,得到的结果应该是确定的(废话)。


一个例子: XOR的One Time Pad(OTP)

M = C = {0, 1}^n, 也就是说密文和明文都是一个01串,长度为n。

密钥: 是一个和密文明文长度一样的随机的01串。

加密算法 E(k, m) = k XOR m

解密算法 D(k, m) = k XOR c

这里的XOR表示异或。


其实,该加密算法是一个Good Cipher(不知道中文一般怎么翻译)

那么对于Good Cipher的定义:

通俗的说,也就是说如果攻击者拿到了密文,他并不能得到明文的任何信息(例如替代密码我们可以通过密文的一些字符的出现概率来推算明文,这就不是一个Good Cipher)

如果是比较严格的定义是

 

这里的k服从均匀分布。

也就是说,如果攻击者拿到了密文c,这时候,他完全不知道c对应的明文是m0还是m1,因为,从m0得到和从m1得到的概率是均等的。


那么该OTP为什么是Good Cipher呢?

证明如下:

    

也就是说,对于任意的m和c,使得E(k,m)=c的概率是满足这个条件的k除以密钥空间的大小|K|(因为k服从均匀分布)

那么对于分子,显然为1,也就是只有1个k能满足E(k,m)=c,而对于分母|K|是定值,因此对于每个明文m来说,P(E(k,m)=c)是定值,因此该OTP是一个Good Cipher。


虽然这个加密算法是一个Good Cipher,但是并不代表这个加密算法能很好的推广使用(因为密钥实在太长了!)

但是,如果一个加密算法是Good Cipher,那么可以得到|K|>=|M|,也就是密钥长度要大于等于要加密的明文长度!

所以,需要有一种方法来减小密钥的长度。


流加密:我们把随机的密钥用伪随机的密钥来替换。

所以需要有一个伪随机生成算法来生成一个伪随机的密钥。

定义伪随机生成器(PRG Pseudo Random Generator):函数G: {0,1}^s --> {0, 1}^n  {0, 1}^s:seed space, n>>s

也就是说,如果我给定一个长度为s的种子,那么根据函数G,可以得到长度为n的伪随机密钥。而n会比s长得多。


那么PRG也有要求

1.生成这个伪随机密钥的算法时间复杂度是可以接受的,就是说要有效率的。

2.生成的伪随机密钥要“看起来”随机。

所以这时候XOR的OTP就要变成下面这种长相:

E(k, m) = m XOR G(k)

D(k, c) = c XOR G(k)

因为这时候我们真正随机的密钥部分长度是比明文密文的长度小很多很多,因此,流密码是没有办法做到完美加密的,也就是他并不是一个Good Cipher。

所以,我们需要来评估一个伪随机生成器是不是安全的。

那么我们就要求PRG得到的伪随机密钥是不可预测的!

也就是说,我如果得到G(k)的前i个字符/bit,那么我就能有一种算法预测第i+1,i+2,...n个。

如果用式子表示,就长着个样子:



而一旦PRG是可预测的,那么就会产生安全问题。

因为,如果攻击者得到了密文,而且他知道其中一小部分的明文,那么就可以推出一小部分的密钥,因为密钥是可预测的,因此他可以算出所有的密钥,然后就可以破解所有的密文了。


那么通过数学来描述,可预测的意思就是

存在一个“有效率”的算法A,而且


也就是说,我存在一个有效率算法,给我密钥的前i位,我有一半多的概率能正确的猜出第i+1位是啥。

这里的要求是不可忽略的。


有了这个定义,有了很多伪随机生成算法就被归为可以预测的,例如

线性同余生成器:随机a,b,r[0]以及质数p,r[i]=(a*r[i-1]+b) mod p

还有glibc的random()函数: r[i] = (r[i-3]+r[i-31]) % 2^32

所以,不能用c语言中的random函数来做PRG!


那么,现在需要再定义一下什么叫可忽略的什么叫不可忽略的。

一般来说,在实际应用中,可忽略的不可忽略的指的是一个数,如果这个数大于,那么就说是不可忽略的,而如果这个数小于,那么就说这个数是可忽略的。

因为,如果这个数大于,那么说明平均在1GB的数据中会出现一次,而如果这个数小于,说明平均起来每个密钥出现不到一次。


但是,这个定义太笼统了,在理论上,可忽略和不可忽略的定义如下:

他是对一个从自然数域到实数域的函数做定义的,

如果这个函数对足够大的x,该函数都小于任意多项式函数的倒数,则说这个函数是可忽略的。

例如,

是可忽略的,因为他的分母是指数的,比多项式增长还快,因此,他比任意多项式函数的倒数增长得慢很多。

而这个是不可忽略的,因为存在多项式比这个式子的分母增长得还快(例如10000次方),因此这个函数是不可忽略的。

也就是说如果要可忽略的话,分母要比多项式函数还高阶。


那么,如果找到了不可预测的PRG,那么是不是怎么使用OTP都行呢?显然不是。

如果一个密钥用来加密了两次,就会出现很大的问题!(Two Time Pad)

考虑到两个明文通过同一个密钥加密:

m1 XOR k = c1

m2 XOR k = c2

那么如果攻击者截获c1和c2,那么可以通过c1 XOR c2得到m1 XOR m2,由于语言(例如英语)他的每个字符的出现概率,那么可以很容易破解出m1和m2。

所以,如果同一个密钥用来加密两次,那么就会出现安全问题。

例如Project Venona:大概就是苏联用了OTP来加密,但是密钥是人工的掷骰子的方式得到的,所以只用来加密一个明文显得特别浪费,所以他们就多次使用了一个密钥加密了不同的明文,然后美英截获了这些加密信息就推算出了明文。

再例如WEP(Wired Equivalent Privacy),采用的是流密码,用的是一个IV(24bit初向量)再连接一串密钥作为加密的密钥,但是,因为只有24bit,因此,再网络繁忙的时候可能短时间内出现密钥的重复,这就会导致被攻击。

所以,我们可以把密钥通过PRG得到任意长度的伪随机串,然后分割出每一段来加密不同的信息,因为PRG得到的是“看起来”随机的,因此,这样就会避免两次使用同样的密钥造成的不安全因素。

当然,OTP并不能用来加密磁盘,例如,我保存一个字符串“To Bob, balalabalabala”,然后保存,这时候,我们得到的是加密的一串密文,这时候,如果我把这个字符串改成“To Eve,balabalabalabala”(也就是只把Bob改成Eve),然后再保存,这时候,如果使用OTP来加密的话,我们可以看到密文中只有三个位置出现了变化,这时候就可以通过Two Time Pad来攻击。

而且,XOR的OTP还有个问题,例如,我现在知道某个地方是加密后的“To Bob”,然后我想要把他变成“To Eve”,这时候可以算出“Bob”和“Eve”之间的异或p,然后把密文异或上p,这时候用户再读出来就变成“To Eve”了。

也就是说,如果我们知道明文是c1,密文是m,然后可以找出m,把它异或上(c1 XOR c2),覆盖m,这时候m=( (c1 XOR k) XOR (c2 XOR c1))=c2 XOR k,这时候用户再读出来就变成了c2。


之前提到PRG得到的伪随机串要“看起来像”随机的,因此我们需要定义下什么叫“看起来像”。因为如果是随机的,那么得到的随机串应该是{0, 1}^n的所有串,而如果给定了PRG和seeds space, 那么其实得到的串会比整个{0, 1}^n 空间小很多很多。但是我们并不希望让攻击者看出我们的随机串看起来不像随机的。

那么我们可以用一种叫统计检验(statistical test)来定义一个串看起来是不是随机的,因此如下定义统计检验:

我们定义{0, 1}^n上的统计检验是一个算法A,这个算法A的输入是一个我们需要做检验的01串,输出0或1,0表示不随机,1表示随机。

举几个例子:

我们可以定义这个算法A为:A(x)=1 iff |#{0(x)}-#{1(x)}|<=10*sqrt(n)   也就是说当且仅当串x中0的数目和1的数目相差不超过10*sqrt(n),那么该算法认为串x随机。

或者定义算法A为:A(x)=1 iff |#{00(x)}-n/4|<=10*sqrt(n)  也就是说当且仅当串0中00子串的数目与n/4相差不超过10*sqrt(n),那么该算法认为串x随机。

或者定义为:当且仅当连续0的个数小于等于10*logn (这里log以2为底),则算法认为串x随机。

当然还可以异想天开很多种定义方法,或者列一个单子说串x满足如下规则则串x是随机的,如果其中有一条不满足则不随机。


那么如何判定一个统计检验的算法是好的还是不好的呢?

我们用一个Advantage函数来定义


这里的k是在K中随机选一个密钥,而r则是在{0,1}^n中随机选一个串。也就是说,这个式子是看统计检验的算法A检测出伪随机生成器G(k)是真随机的概率和检验出一个真正随机的串r是真随机的概率之间差了多少。

那么意味着,如果这个Adv值越大,则说明这个统计检验算法越能区分出伪随机G和真随机,而这个Adv值越小,则说明统计检验算法越难区分出伪随机G和真随机。

例如一个很弱智的算法A,无论塞给他什么串,他都说这个串是真随机的,那么无论什么样的伪随机生成算法G,这个算法的Adv值都为0,因此,说明这个算法根本区分不出G和真随机之间的差别。


那么如果一个PRG算法无论我用什么统计检验的算法都无法将它和真随机区分开,我们就说这个PRG是安全的(secure PRG)。

说的官方一点,就是,对于所有“有效的”统计检验算法A,Adv_PRG[A,G]都是可忽略的,那么说明这个PRG是安全的。

那么,问题来了,我们是否能构造一个PRG并且来证明他是安全的呢?

不好意思,这是个NP问题,但是,我们可以证明,如果PRG是可以预测的话,那么它一定是不安全的。

也就是说,如果PRG要是安全的,那么它一定不可预测。

证明如下:


如果一个PRG是可以预测的,那么假设A是用来预测的算法,那么根据可以预测的定义,满足该式子:

,这里的eps是不可忽略的。

那么我们就可以定义一个统计检验的算法B:

当满足时,B(x)=1,否则,B(x)=0

因此,我们现在算算Adv的值:


注意着里的P[B(r)=1]等于0.5,因为r是{0,1}^n中均匀分布的,因此第i+1位是0还是1跟前i位并没有什么关系,所以值为0.5。

这里的epsilon是不可忽略的,因此意味着我们找到了一个统计检验算法B,能够区别真随机和该随机算法G,因此这个PRG是不安全的。


另外,值得注意的是,如果一个PRG是不可预测的,那么这个PRG是安全的。

因为,对于所有的i来说,如果G在i处为不可预测的,那么意味着我没办法预测下一位是0还是1,那统计检验也就没有办法预测了。

也就是说,综上,PRG不可预测和PRG安全应该是充要条件。


我们可以把上面的概念拓展一下:

如果P1和P2是{0,1}^n中的两个分布,如果这两个分布是computationally indistinguishable的(照例不知道该翻译成什么,或许是,计算不可区分?),那么也就是说:

对于所有的有效率的统计检验A,

,其中前一部分的x服从P1分布,后一部分的x服从P2分布。


那么我们说,如果一个PRG是安全的,那么这个PRG得到的流密码也是安全的,那么什么是安全的流密码呢?

考虑到如果一个攻击者,那么他希望得到的是一部分的明文,因为如果PRG是可预测的,那么得到这部分明文就意味着所有的明文很有可能都被获取到了。

那么我们可以试图来定义什么叫安全的流密码。

或许我们可以考虑,攻击者获取不到密钥,这样可以吗?

那么如果我们有一个很2B的加密算法,就是输入什么串,加密后还是原样输出,也就是E(k,m)=m,那这样攻击者根本不需要获得密钥也就能得到明文信息,那么这么定义肯定是不行的。

那或许说,攻击者获取不到所有的明文呢?

我们也可以定义一个很2B的加密算法:E(k,m0||m1)=m0||E(k,m1),其中||表示两个串相连。那么这么加密意味着攻击者可能获取不到所有的明文,但是我们有信息(m1)泄露给攻击者了。

所以,我们回到原来定义什么是Good Cipher?就是攻击者获得了密文,他也没办法得到明文的任何信息,也就是说如果我随机取密钥的话,不同的明文都有同样的可能加密成这个样子。

那么我们是不是可以这么定义说,如果对于任意的m0和m1,且|m0|=|m1|,如果我等概率在K中取密钥k,E(k,m0)和E(k,m1)在{0,1}^n中需要有一样的分布。

但是,我们之前说了,当密钥长度很小的时候,我们做不到这样,所以我们必须弱化我们的定义:

我们不要求E(k,m0) 和 E(k,m1)有一样的分布,但是这两个分布是computationally indistinguishable的话,我们也能够接受,而且我们可以不要求他对所有的m0和m1都满足这个条件,只需要对攻击者知道的m0和m1满足这个条件就行了。

所以我们可以定义一个语义安全(Semantic Security):

考虑一个场景:假设攻击者告诉你m0和m1,然后你随机在密钥空间里等概率抓一个密钥过来,然后又随机选择m0或m1加密后传给他,这时候,让他来猜猜我加密的到底是m0呢还是m1呢,如果他猜不到,那么就说这是语义安全的。

用式子表示就是,假设W_b表示我加密了m_b,然后给攻击者,他告诉我说我加密的是m1。

那么我们可以定义Adv函数:


其实这里的W0表示的是错的情况(也就是我加密的是m0,他告诉我说我加密的是m1),W1表示的是猜对的情况(我加密的是m1,他成功的猜测说我加密的就是m1)。

如果这个Adv值是趋近于0的话,说明攻击者在瞎猜,也就是说他根本就读不出密文中的任何信息,猜对和猜错的概率都一样

而如果这个Adv值趋近于1的话,说明攻击者在有目的性的猜,他其实是可以根据密文分辨m0和m1的。


那么我们就可以形式化的定义语义安全:

如果E是语义安全的话,那么对于所有的“有效率的”算法A,Adv_SS[A,E]都是可以忽略的。


可以证明的是:OTP是语义安全的。

而且,我们知道,因为密钥的长度小于明文的长度,因此,流密码不可能会是完全安全的,但是,如果我们通过安全的PRG得到的流密码将会是语义安全的。

你可能感兴趣的:([Stanford Cryptography I] Week1)