简介
Blowfish是由Bruce Schneier在1993年创造的对称密钥分组加密算法,相似的DES和AES都是分组加密算法,Blowfish是用来代替DES算法呈现的,并且Blowfish是没有商用限度的,任何人都能够自在应用。
比照而言,尽管AES也是一种明码强度很高的对称明码算法,然而如果须要商用的话要向NIST领取受权费用。
blowfish详解
blowfish和DES一样,应用的是feistel明码来进行分组加密。blowfish的分组块大小是64bits,可变密钥长度能够从32bits到448bits不等。
blowfish须要进行16轮的feistel加密操作,咱们先从下图大抵感受一下blowfish算法的加密流程:
大略的流程就是将P(原始数据)分成左右两局部,先拿右边的局部和Kr 做异或操作,得出的后果调用F函数,最初将F函数的输入后果和右半局部进行异或操作。
调换左右局部的地位,持续进行这样的操作,总共进行16轮就失去了最终的加密后果。
大家能够看到整个加密过程中最重要的两个变量就是Kr 和 F函数。
接下来咱们会具体进行解说。
密钥数组和S-box
密钥数组
从图上咱们能够看到,Kr 的范畴是从K1 到 K18 。总共有18个密钥组成的数组。 每个密钥的长度是32位。
咱们来看一下密钥数组是怎么生成的。
首先咱们应用随机数来对密钥数组进行初始化。怎么能力生成一个足够随机的32位数字呢?
一个很罕用的办法就是应用常量的小数局部,将其转换成为16净值,如下所示:
K1 = 0x76a301d3
K2 = 0xbc452aef
...
K18 = 0xd7acc4a5
还记得blowfish的可变密钥的长度吗?是从32bits到448bits,也就是从1到14个32位的数字。咱们用Pi来示意,那么就是从P1到P14总共14个可变密钥。
接下来咱们须要应用K和P进行操作,从而生成最终的K数组。
咱们应用K1和P1进行异或操作,K2和P2进行异或操作,始终到K14和P14。
因为P只有14个值,而K有18个值,所以接下来咱们须要重复使用P的值,也就是K15和P1进行异或,K16和P2进行异或,直到K18和P4。
将异或之后的值作为新的K数组的值。
当初咱们取得了一个新的K数组。
留神,这个K数组并不是最终的数组,咱们接下来看。
S-box
在生成最终的P数组之前,咱们还要介绍一个概念叫做S-box。
在密码学中,s-box的全称是substitution-box,也就是一个替换盒子,能够将输出替换成不同的输入。
S-box 接管 n个bits的输出,而后将其转换成m个bits的输入。
这里n和m能够是不等的。
咱们看一下DES中S-box的例子:
下面的S-box将6-bits的输出转换成为4-bits的输入。
S-box能够是固定的,也能够是动静的。比方,在DES中S-box就是动态的,而在Blowfish和Twofish中S-box就是动静生成的。
Blowfish算法中的F函数须要用到4个S-box,F函数的输出是32bits,首先将32bits分成4份,也就是4个8bits。
S-box的作用就是将8bits转换成为32bits。
咱们再具体看一下F函数的工作流程:
S-box生成的值会进行相加,而后进行异或操作。最终失去最终的32bits。
S-box的初始值也能够跟K数组一样,应用常量的小数局部来初始化。
生成最终的K数组
在下面两节,咱们生成了初始化的K数组和S-box。
blowfish认为这样还不够平安,不够随机。
咱们还须要进行一些操作来生成最终的K数组。
首先咱们取一个全为0的64bits,而后K数组和S-box,利用blowfish算法,生成一个64bits。
将这个64bits分成两局部,别离作为新的K1 和 K2。
而后将这个64bits作为输出,再次调用blowfish算法,作为新的K3 和 K4。
顺次类推,最终生成所有K数组中的元素。
4个S-box的数组也依照下面的流程来进行生成。从而失去最终的S-box。
blowfish
有了最终的K数组和S-box,咱们就能够真正的对要加密的文件进行加密操作了。
用个伪代码来示意整个流程:
uint32_t P[18];uint32_t S[4][256];uint32_t f (uint32_t x) { uint32_t h = S[0][x >> 24] + S[1][x >> 16 & 0xff]; return ( h ^ S[2][x >> 8 & 0xff] ) + S[3][x & 0xff];}void encrypt (uint32_t & L, uint32_t & R) { for (int i=0 ; i<16 ; i += 2) { L ^= P[i]; R ^= f(L); R ^= P[i+1]; L ^= f(R); } L ^= P[16]; R ^= P[17]; swap (L, R);}void decrypt (uint32_t & L, uint32_t & R) { for (int i=16 ; i > 0 ; i -= 2) { L ^= P[i+1]; R ^= f(L); R ^= P[i]; L ^= f(R); } L ^= P[1]; R ^= P[0]; swap (L, R);} // ... // initializing the P-array and S-boxes with values derived from pi; omitted in the example // ...{ for (int i=0 ; i<18 ; ++i) P[i] ^= key[i % keylen]; uint32_t L = 0, R = 0; for (int i=0 ; i<18 ; i+=2) { encrypt (L, R); P[i] = L; P[i+1] = R; } for (int i=0 ; i<4 ; ++i) for (int j=0 ; j<256; j+=2) { encrypt (L, R); S[i][j] = L; S[i][j+1] = R; }}
blowfish的利用
从下面的流程能够看出,blowfish在生成最终的K数组和S-box须要消耗肯定的工夫,然而一旦生成结束,或者说密钥不变的状况下,blowfish还是很疾速的一种分组加密办法。
每个新的密钥都须要进行大略4 KB文本的预处理,和其余分组明码算法相比,这个会很慢。
那么慢有没有益处呢?
当然有,因为对于一个失常利用来说,是不会常常更换密钥的。所以预处理只会生成一次。在前面应用的时候就会很快了。
而对于歹意攻击者来说,每次尝试新的密钥都须要进行漫长的预处理,所以对攻击者来说要破解blowfish算法是十分不划算的。所以blowfish是能够抵挡字典攻打的。
因为blowfish没有任何专利限度,任何人都能够收费应用。这种益处促成了它在明码软件中的遍及。
比方应用blowfish的bcrypt算法,咱们会在前面的文章中进行解说。
blowfish的毛病
Blowfish应用64位块大小(与AES的128位块大小相比)使它容易受到生日攻打,特地是在HTTPS这样的环境中。 2016年,SWEET32攻打演示了如何利用生日攻打对64位块大小的明码执行纯文本复原(即解密密文)。
因为blowfish的块只有64bits,比拟小,所以GnuPG我的项目倡议不要应用Blowfish来加密大于4 GB的文件。
除此之外,Blowfish如果只进行一轮加密的话,容易受到反射性弱键的已知明文攻打。 然而咱们的实现中应用的是16轮加密,所以不容易受到这种攻打。然而Blowfish的发明人布鲁斯·施耐尔(Bruce Schneier)还是倡议大家迁徙到Blowfish的继承者Twofish去。
本文已收录于 http://www.flydean.com/blowfish/
最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
欢送关注我的公众号:「程序那些事」,懂技术,更懂你!