Twofish加密算法详解

<style type="text/css"> .p9 { font-size:9pt; text-decoration:none; } a:link { color:#000099; text-decoration:none; } a:visited { color:#000099; text-decoration:none; } a:hover { color:#FF3333; text-decoration:underline; } .pediy { font-size:9pt; }</style> <blockquote2></blockquote2>

TITLE:Twofish加密算法详解
AUTHOR:lionel@nkbbs.org
BLOG:http://lionel.blogchina.com
DATE:01/08/2005

CONTENT:这几天分析一软件,发现其序列号用到了Twofish加密算法,上网找了很久
都没有找到相应的中文资料,于是决定等我研究明白之后写一篇文档,以便
给今后需要使用Twofish的人以参考,下面进入正题。

首先介绍一下Twofish的历史,如果您只想了解如何运用此算法,请直
接跳到下一段。在1972到1974年中,NationalBureauofStandards(现在
更名为NationalInstituteofStandardsandTecnology,缩写为NIST)首
次公开征求一种标准的数据加密算法,结果产生了DES(DataEncryption
Standard)加密算法。但DES的密钥长度对于现在计算机的运行速度来说,
在某些高机密的场合显得有点不足,已经不再安全。所以1999年NIST决定采
用一种更高标准的加密算法AES(AdvancedEncryptionStandard)来代替原
来的DES。首先这种加密算法必须是块加密(blockcipher),因为块加密可
以被用来对数据流进行加密,也可以被用来制造一些专用的数据加密设备。
其次,这种加密算法必须使用更长的密钥,更大的加密块,更高的加密速度,
更高的灵活性。Twofish则是counterpane公司向NIST提交的一种满足AES
要求的加密算法。Twofish采用128位数据块(128bitsblock),128-192-
256-bit可变长度密钥。Twofish算法是进入NIST第二轮5种加密算法中的
一种。下面分步详细讲解如何使用Twofish加密算法。

现在网上能找到的大部分Twofish的源程序都是外国人写的,还可以找
到有一些TwofishSDK。但它们普遍代码庞大,使用起来都不太方便,不如
根据自己的需要,自己写一个代码。我写了一个可以用Twofish进行加密解
密的代码,才不过400行,所以在看下面的文章之前,你首先要对自己有信
心,因为其中用到了一些数学知识。你也可以参考Twofish的官方文档:

http://www.counterpane.com/twofish.html

其中paper-twofish-paper.pdf有68页,全英文,还不如看我这篇文章来
的快,呵呵,不过你可以把它与本文互相参照着看。

Twofish加密算法的流程图如下:

┌───────────────────────────────┐
│P(128bits)│
└┬───┬─────────────────────┬───┬┘
││││
⊙←K0⊙←K1<-inputwhitening->K2→⊙K3→⊙
││││
││┌┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┐││
││┆F┆││
││┆┌┄┄┄┄┄┄┄┄┄┐┆│<<1│
││┆┆g┆K(2r+8)┆││
││┆┆┌─┐┆│┆││
││┆┆┌S-box0->││┆┌┄┄┄┐│┆││
││┆┆├S-box1->│M│┆┆PHT┆↓┆↓│
├───┼┼┼→││D├┼┼→⊙┬┼→⊙┼→⊙│
││┆┆├S-box2->│S│┆┆↑│┆┆││
││┆┆└S-box3->││┆┆││┆┆││
││┆┆└─┘┆┆││┆┆││
││┆└┄┄┄┄┄┄┄┄┄┘┆││┆┆││
││┆┌┄┄┄┄┄┄┄┄┄┐┆││┆┆││
││┆┆g┆┆││┆┆││
││┆┆┌─┐┆┆││┆┆││
││┆┆┌S-box0->││┆┆││┆┆││
││┆┆├S-box1->│M│┆┆││┆┆│↓
│<<8├┼┼→││D├┼┼─┴⊙┼→⊙┼─┼──→⊙
││┆┆├S-box2->│S│┆┆┆↑┆││
││┆┆└S-box3->││┆└┄┄┄┘│┆││
││┆┆└─┘┆│┆││
││┆└┄┄┄┄┄┄┄┄┄┘K(2r+9)┆││
││└┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┘│>>1│
││││
│└─────────┐┌────────┘│
│╲╱│
└─────────────┐╳┌────────────┘
╳╳
┌─────────────┘╳└────────────┐
│┌──────────┘└─────────┐│

......15morerounds......

│└─────────┐┌────────┘│
│╲╱│
└─────────────┐╳┌────────────┘
╳╳
┌─────────────┘╳└────────────┐
│┌──────────┘└─────────┐│
↓↓↓↓
⊙←K4⊙←K5<-outputwhitening->K6→⊙→K7⊙
↓↓↓↓
┌───────────────────────────────┐
│C(128bits)│
└───────────────────────────────┘

怎么样?看完之后有点晕了吧?里面有很多英文的术语,我不知道对应
的中文怎么说,所以索性下面的术语就直接都用英文的好了。在讲解每一步
具体如何计算之前我们先做一些准备工作,说明一下其中字母各代表什么。
其中开始处P(plaintext)表示需要进行加密的128-bit数据,也即16字节。
然后将这16字节分为4组,每组32-bit,即4字节。在循环之前首先对这4
组数据分别用K0K1K2K3进行异或操作,称之为inputwhitening,然后对
异或后的数据分组进行计算。计算后将1-32-4组的数据对换,如此循环15
次,再1-32-4对换一次。对这4组数据分别用K4K5K6K7异或操作,称
之为outputwhitening。最后将这4组数据组合成16字节的数据,也就是
最后的密文C(ciphertext),长度跟加密前的P同样是128-bit。下面详细
说明每一计算步骤。

1.计算前的准备工作

加密前的plaintext是128bits,也就是16bytes。假设这16bytes分
别是p0,...,p15。用little-endianconversion(如果你不明白,可以参
看我的blog中的的一篇相关文章),将p0,...,p15分为4组:

P(i)=∑p(4i+j)2^(8j),其中i,j=0,...,3

2.Inputwhitening

R(0,i)=P(i)xorK(i),其中i=0,...,3

这里的K(i)是跟据密钥算出来的32-bit数据,计算方法后面介绍。
3.16次循环

在16次循环的每一次中,4组数据的前两组与当前循环次数通过F进行
计算,计算出2组数据。第3组数据与计算出的第1组数据异或,然后向右
循环移动一位。第4组数据向左循环移动一位,然后异或计算出的第2组数
据。然后将1-32-4组数据对换,作为下一轮计算的数据。程序表示如下:

(F(r,0),F(r,1))=F(R(r,0),R(r,1),r)
R(r+1,0)=ROR(R(r,2)xorF(r,0),1)
R(r+1,1)=ROL(R(r,3),1)xorF(r,1)
R(r+1,2)=R(r,0)
R(r+1,3)=R(r,1)

4.Outputwhitening

C(i)=R(16,(i+2)mod4)xorK(i+4),其中i=0,...,3

这里的K(i+4)同样是根据密钥计算出来的32-bit数据,目前为止总共有

K(i)i=0,...,7

5.计算后组成密文

c(i)=[C(i/4)/2^(8(imod4))]mod2^8,其中i=0,...,15

这样,128-bit的C就计算出来了。
前面的K(i)和函数F还没有说明,下面先介绍函数F。

1.TheFunctionF

(F0,F1)=F(R0,R1,r)

其中参数R0,R1是32-bit数据,r表示当前循环的次数,T0,T1是计算
出的结果,同样都是32-bit的数据。

T0=g(R0)
T1=g(ROL(R1,8))
F0=(T0+T1+K(2r+8))mod2^32
F1=(T0+2T1+K(2r+9))mod2^32

其中后两步计算被称为PHT(Pseudo-HadamardTransforms)。
这里K(i)i=8,...39,加上前面的i=0,...,7,所以总共有40个K

K(i)i=0,...,39

我们仍然先不讲如何计算K,而先介绍函数g。

2.TheFunctiong

Z=g(X)

函数g是Twofish算法的核心,也是比较难理解的一部分。其中参数X
与计算结果Z都是32-bit的数据。

x(i)=[X/2^(8i)]mod2^8,其中i=0,...,3
y(i)=s(i)(x(i)),其中i=0,...,3
┌┐┌┐┌┐
│z0││││y0│
│z1│=│MDS│·│y1│
│z2││││y2│
│z3││││y3│
└┘└┘└┘
Z=∑z(i)2^(8i),其中i=0,...,3

首先将32-bit的参数X分为4个字节x0,...,x4,然后每一个x(i)分
别进入自己的S-box,其中每一个S-box都是8-bit输入,8-bit输出。这样
计算出来的y(i)仍然是8-bit,组成一个4*1的列向量,这个向量与定义
在GF(2^8)上的4*4MDS矩阵相乘,得到4*1的列向量。最后将这个列向量中
的四个元素组成32-bit数据Z。其中MDS矩阵为:

┌┐
│01EF5B5B│
MDS=│5BEFEF01│
│EF5B01EF│
│EF01EF5B│
└┘

为了数据的计算,还必须明确定义GF,对于MDS矩阵,GF的定义如下:

GF(2^8)≡GF(2)(x)/v(x),其中v(x)=x^8+x^6+x^5+x^3+1

又不太明白了吧?上面不太容易理解的地方有两处,一个是S-boxes,一个
是在有限域GF上如何进行计算。对于前一个问题,我们将会在下面进行介绍,
对于后一个问题,我将会专门写一篇在有限域上进行计算的文章,如果你感
兴趣可以去我的blog。

我们再总结一下吧,目前还有哪些问题没有解决:

K(i),i=0,...,39

s(i)(),i=0,...,3

以上这两组数据都是通过密钥计算出来的(key-dependent),所以下面我们
该介绍一下密钥了。

3.TheKeySchedual

在这一部分,我们需要产生40个与密钥相关的K(i),和4个与密钥相关
的,在函数g中使用到的S-box,也就是s(i)()。

在Twofish算法中,规定密钥的长度N=128,N=192,N=256三种。
也就是说密钥的长度可以在128-bit~256-bit之间变化。

我们记k=N/64(则k=2,3,4),那么密钥M也就由8k个字节组
成。我们记这8k个字节为:

m0,...,m(8k-1)

首先将这8k个字节转换成2k个32-bit的数据:

M(i)=∑m(4i+j)2^(8j),其中j=0,...,3,i=0,...,2k-1

然后由这2k个32-bit数据构成两个k维的向量:

Me=(M0,M2,...,M(2k-2))
Mo=(M1,M3,...,M(2k-1))

下面再利用m(i)产生一个k维的向量:

┌┐┌┐┌┐
│s(i,0)││││m(8i)│
│s(i,1)│=│R│·│m(8i+1)│
│s(i,2)││S││......│
│s(i,3)││││m(8i+7)│
└┘└┘└┘

其中RS是定义在GF(2^8)的4*8阶矩阵。记:

S(i)=∑s(i,j)2^(8j),其中j=0,...,3,i=0,...,k-1

这样就有产生了一个k维向量:

S=(S(k-1),S(k-2),...,S0)

注意,这里S是由S(i)反序组成的。对于RS矩阵,我们同样需要明确定义有
限域GF(2^8)。在这里:

GF(2^8)≡GF(2)[x]/w(x),其中w(x)=x^8+x^6+x^3+x^2+1

┌┐
│01A455875A58DB9E│
RS=│A45682F31EC668E5│
│02A1FCC147AE3D19│
│A455875A58DB9E03│
└┘

这里定义的MeMoS构成了keyschedual的基础。

3.1AdditionalKeyLengths

这里介绍一下密钥长度的问题。密钥长度必须是小于256bits的,如果
密钥长度不足上面给丁的N,那么在密钥后面补零,直到最接近的N为止。
例如密钥长度是80-bit,则在m0,...,m9后面加上:

m(i)=0,i=10,...,15

这样就构成了一个128-bit的密钥。

3.2TheFunctionh

你一定觉得奇怪,怎么突然有出来个h函数,上面明明没有遇到啊?!
呵呵,上面是没有遇到,不过下面就快用到了,而且这个函数很重要。

Z=h(X,L)

其中X,Z是32-bit的数据,L=L(L0,...,L(k-1))是一个k维的向量。
首先我们还是将X,L分成字节:

l(i,j)=[L(i)/2^(8j)]mod2^8i=0,...,k-1
x(j)=[X/2^(8j)]mod2^8j=0,...,3

我们记:

y(k,j)=x(j)j=0,...,3

如果:k==4

y(3,0)=q1[y(4,0)]xorl(3,0)
y(3,1)=q0[y(4,1)]xorl(3,1)
y(3,2)=q0[y(4,2)]xorl(3,2)
y(3,3)=q1[y(4,3)]xorl(3,3)

如果:k>=3

y(2,0)=q1[y(3,0)]xorl(2,0)
y(2,1)=q1[y(3,1)]xorl(2,1)
y(2,2)=q0[y(3,2)]xorl(2,2)
y(2,3)=q0[y(3,3)]xorl(3,3)

对于所有情况:

y0=q1[q0[q0[y(2,0)]xorl(1,0)]xorl(0,0)]
y1=q0[q0[q1[y(2,1)]xorl(1,1)]xorl(0,1)]
y2=q1[q1[q0[y(2,2)]xorl(1,2)]xorl(0,2)]
y3=q0[q1[q1[y(2,3)]xorl(1,3)]xorl(0,3)]

也就是说,如果k==4,那么上面3种情况都要做;如果k==3,那么只做后两
种情况;如果k==2,则只计算最后这种情况。

┌┐┌┐┌┐
│z0││││y0│
│z1│=│MDS│·│y1│
│z2││││y2│
│z3││││y3│
└┘└┘└┘

Z=∑z(i)2^(8i),其中i=0,...,3

最后的矩阵乘法同样遇到MDS矩阵,GF(2^8)的定义跟前面一样。
h函数讲完了,但其中又多出来个q0q1,它们同样是S-boxes,过一会我们
再讲如何计算q0q1,下面开始介绍如何计算S-boxes与K(i)。

3.3TheKey-dependentS-boxes

我们用下面的映射来定义g中使用到的4个S-boxes:

g(X)=h(X,S)

其中S是上面计算出来的k维向量。
这样g中出现的s(i)()就可以用h(X,S)来解决了。

3.4TheExpandedKeyWordsK(i)

下面介绍如何计算K(i):

p=2^24+2^16+2^8+2^0
A(i)=h(2ip,Me)
B(i)=ROL(h((2i+1)p,Mo),8)
K(2i)=(A(i)+B(i))mod2^32
K(2i+1)=ROL((A(i)+2B(i))mod2^32,9)

这里i=0,...,19

3.5ThePermutationsq0andq1

q0q1是有256个元素的数组,数组中的元素是8-bit的。它们的构成方

法如下:

a0,b0=[x/16],xmod16
a1=a0xorb0
b1=a0xorROR(b0,1)xor8a0mod16
a2,b2=t0[a1],t1[b1]
a3=a2xorb2
b3=a2xorROR(b2,1)xor8a2mod16
a4,b4=t2[a3],t3[b3]
y=16b4+a4

这里a(i)b(i)都是4-bit的,其中的ROR运算也是4-bit的。这样利用上面的
公式,就将一个16-bit的x映射到一个16-bit的y,我们把当x=i的时候
y的值定义为q[i],这样当x=0,...255时,也就求出了q[i]中的256个元
素。对于q0q1,上述公式中的t0t1t2t3分别定义如下:

对于q0:

t0=[817D6F320B59ECA4]
t1=[ECB81235F4A6709D]
t2=[BA5E6D90C8F32471]
t3=[D7F4126E9B3085CA]

对于q1:

t0=[28BDF76E31940AC5]
t1=[1E2B4C376DA5F908]
t2=[4C75169A0ED82B3F]
t3=[B951C3DE647F208A]

这样,Twofish算法的全部计算过程我就讲完了,其中说的不够详细的地方
大家可以参看官方的文档,或者网上下载的源程序。这篇文章中有几处没有

详细说明:

1.如何根据定义g(X)=h(X,S)求出相应的S-boxes
2.如何在有限域GF(2^8)上进行矩阵运算

其实上面这两个问题都是关于有限域(finitefield)的,如果直接按照
定义去计算,运算过程十分复杂。但MDS与RS矩阵都有各自的特点,所以
在写程序的时候可以将运算化简。对于Twofish算法中,有限域的更进一步
讨论我将再专门写一篇文章,有兴趣的朋友可以关注一下我的blog。

另外我要说是,在Twofish算法中,可以使用几种加密模式,例如:

ECB(electroniccodebook)
CBC(cipherblockchain)

等等,如果我有精力继续写文档我会不定期的发布在我的blog上,最后再贴
一下我的blog,算是一个小小的宣传,呵呵:

http://lionel.blogchina.com

欢迎大家去我的blog继续讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值