Blowfish是一种对称区块加密算法。该算法流程分为密钥扩展以及数据加密俩部分,每次分组长度为64位,密钥采用32-448位,经过扩展后生成多个子密钥数组。进行共16轮的迭代加密。
加密流程图:
接收分组长度为64bit的明文,将其分为L和R各32bit。和P进行异或以及F函数加密然后交换迭代16轮,得到密文。
伪代码:
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);
}
// ...
//使用从 pi 派生的值初始化 P 数组和 S 盒; 示例中省略
// ...
{
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;
}
}
具体加密流程:
如何生成长度为18的P数组(18个32bit的子密钥)?
最常用的方法就是使用常量π的小数部分,将其转换成为16净值,如下所示:
K1 = 0x76a301d3
K2 = 0xbc452aef
…
K18 = 0xd7acc4a5
而Blowfish算法的可变密钥长度为32bit到448bit,1到14个32位的数字。使用可变密钥和Pi进行依次异或,也就是伪代码中的:
for (int i=0 ; i<18 ; ++i)
P[i] ^= key[i % keylen];
这样就可以的到P数组了。
S-box是一个随机生成的替换盒子,一共有四个,用于F轮函数加密。类似于DES中的S盒将6bit的明文转换成4bit的大小,Blowfish中的S-box作用就是将8bit的数据转换成32bit。S-box的生成也可以和P数组一样使用常量π的小数部分。
之后,取一个全为0的64bits,然后P数组和S-box,应用blowfish算法,生成一个64bits。之后将这个64bits作为输入再次调用blowfish算法,这样最终生成了一个新的P数组:
uint32_t L = 0, R = 0;
for (int i=0 ; i<18 ; i+=2) {
encrypt (L, R);
P[i] = L; P[i+1] = R;
}
获得了最终的P数组和S-box后,就可以开始数据加密部分了。下面是Blowfish轮函数的处理
Blowfish的轮函数(Feistel)
64bit的明文经过拆分成L和R后,L和P1异或后还是32bit;L异或后的值作为下一轮迭代的R,同时L会进行一次轮函数的加密,32bits会被划分为4个8bit大小的数据,经过S-box被替换成4个32bits大小的数据,之后进行相加和异或的操作,得到的新L会与R进行异或;异或后的值存储在R中,作为下一轮迭代的L。
这样一次迭代就完成了。经过了16次迭代后,P数组中还剩下俩个数据没有被使用。需要单独拿出来进行异或操作。
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);
}
这样。Blowfish的全部流程就结束了。
可以使用crypto库进行加解密。
from Crypto.Cipher import Blowfish
key=b'input your key'
bf=Blowfish.new(key,Blowfish.MODE_ECB)
enc=b"input your enc"
print(bf.decrypt(enc))
参考:
https://www.cnblogs.com/flydean/p/14911114.html
https://cloud.tencent.com/developer/article/1836650