??xml version="1.0" encoding="utf-8" standalone="yes"?>
本文针对Rijndael加密法的数学理景,法的架构,回合的{换,金钥的生,以及各种d破密法等{,做了一些简单的介绍?/span>
一、简?/span>
?/span>AES ( Advanced Encryption Standard ) 的选拔中,从最初的十五个算法,到十个、五个,逐步{选出适合用来作ؓ下一代加密算法的标准?/span>Rijndael在经q了一番时日的考验之后Q也一直名列前矛。直?st1:chsdate Year="2005" Month="10" Day="2" IsLunarDate="False" IsROCDate="False" w:st="on">十月二日Q?/span>Rijndael才脱颖而出Q这文章便是针?/span>Rijndael作简要的介绍?/span>
Rijndael是一个反复运的加密法Q它允许可变动的数据区块及金钥的长度。数据区块与金钥长度的变动是各自独立的?/span>
?/span>Rijndael法中定义了几个名词Q分q如下:
StateQ在q算q程中所产生的中间|是一?/span>4×Nb的矩阵,Nb可由数据长度除以32位求得,也就是把数据分割?/span>Nb个区块?/span>
Cipher KeyQ用来做加密q算的金钥,形式是一?/span>4×Nk的矩阵,Nk可由金钥长度除以32位求得,也就是把金钥分割?/span>Nk?/span>32位的子金钥?/span>
?/span>Rijndael法中,q算的回合数(Nr)是由Nb?/span>Nk所军_的,回合数的变动定义如下表?/span>
Nr |
Nb=4 |
Nb=6 |
Nb=8 |
Nk=4 |
10 |
12 |
14 |
Nk=6 |
12 |
12 |
14 |
Nk=8 |
14 |
14 |
14 |
二?/span>Rijndael的数学背?/span>
?/span>Rijndael中用了许多字节层的运,而这些运是?/span>GF(28)为基架构。也有一些采用了4-byte的字l运。在q部分,我们介l这些基本的数学原理?/span>
(1) GF(28)的定?/span>
假设一个字?/span>b?/span>b7b6b5b4b3b2b1b0l成Q我们可以把q些bi惌成一?/span>7ơ多式的系敎ͼ而这些系C?/span>0是1Q?/span>
b7 x7+ b6 x6+ b5 x5+ b4 x4+ b3 x3+ b2 x2+ b1 x + b0Q?/span>
例如Q?/span>(57)16的二q制表示法ؓ(0101,0111)2表示成多式Q则为:
x6+ x4+ x2+ x + 1 .
(2) 加法
两个多项式的加法Q则是定义ؓ相同指数的pL和再模余2Q简单的说就是作EXORq算(i.e., 1+1=0)。例如:
(57)16+(83)16=(01010111)2+(10000011)2 = (11010100)2 = (D4)16
或是(x6+x4+x2+x+1) + (x7+x+1) = x7+x6+x4+x2
(3) 乘法
在乘法里面,多项式相乘之后的l果很容易造成溢位的问题,解决溢位的方式是把相乘的l果Q再模余一个不可分解的多项?/span>m(x)。在Rijndael中,定义一个这样子的多式?/span>
m(x)=x8+x4+x3+x+1或是(11B)16
例如Q?/span>
(57)16?/span>(83)16 = ( x6+ x4+ x2+ x + 1)?/span> ( x7+ x + 1) = x13+ x11+ x9+ x8+ x7+x7+ x5+ x3+ x2+x+x6+ x4+ x2+ x + 1
= (x13+ x11+ x9+ x8+ x6+ x5+ x4+ x3+ 1+x13+ x11+ x9+ x8+ x6+ x5+ x4+ x3+ 1) modulo (x8+ x4+ x3+ x + 1)
= x7+ x6+ 1=(C1)16
(4) 乘以x
若把b(x)乘上xQ得?/span>b7 x8+ b6 x7+ b5 x6+ b4 x5+ b3 x4+ b2 x3+ b1 x2 + b0x。若b7=0Q不会发生溢位问题,{案x正确的;?/span>b7=1Q发生溢位问题,必须减去m(x)。我们可以把q种q算表示?/span>xtime(x)Q其q算方式?/span>left shift(若溢位则?/span>(1B)16?/span>EXORq算)Q例如:‘57’ · ‘13’ = ‘FE’
‘
‘
‘
‘
‘
三?/span>Rijndael的加密架?/span>
Rijndael加密法是由一?/span>initial Round Key additionQ?/span>Nr-1个回合运,及一?/span>final round所l成。加密过E以C语言伪码叙述如下Q?/span>
Rijndael(State, CipherKey)
//state表示输入的数据明文,
//CipherKey表示使用的加密金钥,
//ExpandedKey表示每个Round使用的子金钥?/span>
{
KeyExpansion(CipherKey, ExpandedKey);
AddRoundKey(State, ExpandedKey);
For ( i=1; i<Nr; i++)
Round(State, ExpandedKey+Nb×i);
FinalRound(State, ExpandedKey+Nb×Nr);
}
上述法中的Key ExpansionQ可以先行计出来,所以加密过E可以简化ؓQ?/span>
Rijndael(State,ExpandedKey)
//State表示输入的数据明文,
//ExpandedKey表示每个Round使用的子金钥?/span>
{
AddRoundKey(State,ExpandedKey);
For( i=1 ; i<Nr ; i++ )
{
Round(State,ExpandedKey + Nb×i) ;
}
FinalRound (State, ExpandedKey + Nb×Nr);
}
各个子运介l如下?/span>
回合转换(Round transformation)Q?/span>
回合转换包含四个不同的工作,其算法如下:
Round(State,RoundKey)
//State表示输入的数据明文,
//RoundKey表示每个Round使用的子金钥?/span>
{
ByteSub(State);
ShiftRow(State);
MixColumn(State);
AddRoundKey(State,RoundKey);
}
法中的l止回合(Final round)包含下列工作目Q?/span>
FinalRound(State,RoundKey)
//State表示输入的数据明文,
//RoundKey表示每个Round使用的子金钥?/span>
{
ByteSub(State) ;
ShiftRow(State) ;
AddRoundKey(State,RoundKey);
}
以下针对每个回合转换的运过E,作一个深入的介绍Q可以更清楚法的过E?/span>
1. 字节取代转换(ByteSub transformation)Q?/span>
字节转换是一个以字节为单位的非线性取代运,取代?/span>(S-Box)是经q两个运过E而徏立,q且是可逆的?/span>
首先扑և每个字节?/span>GF(28)中的乘法反元素;
接着l过一个仿?/span>(Affine)转换q算Q定义如下:
(本图摘录自参考文?/span>[1])
字节取代(ByteSub)q算?/span>State的媄响,如下图所C:
(本图摘录自参考文?/span>[1])
字节取代(ByteSub)转换的反q算Q?/span>
计算仿射对应之后的相反运可得到S-1-BoxQ以?/span>S-1-Box做字节取?/span>(ByteSub)卛_?/span>
2. Ud转换( ShiftRow transformation )Q?/span>
在这个{换中Q?/span>State的每一列以不同的偏U量做环状位U,W?/span>0列不动,W一列位U?/span>C1个字节,W二列位U?/span>C2个字节,W三列位U?/span>C3个字节。位Uȝ偏移?/span>C1,C2,C3跟区块的数目(Nb)有关Q定义如下表Q?/span>
Nb |
C1 |
C2 |
C3 |
4 |
1 |
2 |
3 |
6 |
1 |
2 |
3 |
8 |
1 |
3 |
4 |
Ud转换(ShiftRow)q算对于State的媄响,囄如下Q?/span>
(本图摘录自参考文?/span>[1])
Ud转换(ShiftRow)的反q算Q?/span>
对第二第三及W四列做Nb-C1,Nb-C2,Nb-C3个字节的环状位移卛_?/span>
3. 淯转换(MixColumn transformation)Q?/span>
在这个{换中Q把State当作一个存?/span>GF(28)中的多项式。ƈ且对一个固定的多项?/span>c(x)作乘法,如果发生溢位Q则再模?/span>x4+1。表C如下:
c(x) = ‘
c(x)?/span>x4+1互质Qob(x) = c(x) Ä a(x)Q以矩阵乘法表示如下Q?/span>
(本图摘录自参考文?/span>[1])
Statel过淯(MixColumn)q算之后的变化如下:
(本图摘录自参考文?/span>[1])
淯(MixColumn)转换的反q算Q则是乘上一个特D的多项?/span>d(x)Q?/span>
(‘
d(x) = ‘0B’x3 + ‘0D’x2 + ‘
4. The Round Key AdditionQ?/span>
q个q算主要是把每一个回合金?/span>(Round Key)透过单的bitwise EXOR加入到每一?/span>State中,以图C如下:
(本图摘录自参考文?/span>[1])
四、金钥的排程(Key Schedule)
回合金钥(Round Key)是从加密金钥(Cipher Key)l过q算产生出来的。金钥排E?/span>(Key Schedule)是由金钥扩充(Key Expansion)及回合金钥的选择(Round Key Selection)l成的,基本的理论如下:
所有回合金钥的M数是把区块长?/span>(block length)乘上回合数加1Q?/span>(?/span>Nr-1个回合,加上一个终止回?/span>(final round))Q例如,128个位的区块长度经q?/span>10个回合运,所需要用到的所有回合金钥的MCؓ1408个位?/span>
加密金钥(Cipher Key)必须扩充为扩充金?/span>(Expanded Key)?/span>
回合金钥是从扩充金钥中选出来的Q选择的方式如下:
W一个回合金钥由?/span>Nb个字l组成,W二个回合金钥由接下来的Nb个字l组成,余此cL?/span>
(1) 金钥的扩?/span>( Key Expansion )Q?/span>
扩充后的金钥是一?/span>4-byte的线性数l,表示?/span>W[Nb×(Nr+1)]。前Nk个字l包含了加密金钥(Cipher Key)?/span>
金钥扩充函式?/span>Nk是息息相关的Q分ZU情况运作,一是当Nk于或等?/span>6Q另外则是当Nk大于6Q以伪码叙述如下Q?/span>
?/span>Nk?/span>6Ӟ
KeyExpansion(byte Key[4×Nk] word W[Nb×(Nr+1)])
{
for(i = 0; i < Nk; i++)
W[i] = (Key[4×i], Key[4×i+1], Key[4×i+2], Key[4×i+3] );
for(i = Nk; i < Nb×(Nr + 1); i++)
{
temp = W[i - 1];
if (i % Nk == 0)
temp = SubByte(RotByte(temp)) ^ Rcon[i / Nk];
W[i] = W[i - Nk] ^ temp;
}
}
在上面的子程序中Q?/span>SubByte(W)传回一?/span>4-byte的字l,q些字组是输入的字组l过S-box的{换所产生的相对字l?/span>RotByte(W)则是传回l过旋{的字l?/span>
?/span>NkQ?/span>6Ӟ
KeyExpansion(byte Key[4×Nk] word W[Nb×(Nr+1)])
{
for(i = 0; i < Nk; i++)
W[i] = (key[4×i],key[4×i+1], key[4×i+2], key[4×i+3] );
for(i = Nk; i < Nb×(Nr + 1); i++)
{
temp = W[i - 1];
if (i % Nk == 0)
temp = SubByte(RotByte(temp)) ^ Rcon[i / Nk];
else if (i % Nk == 4)
temp = SubByte(temp);
W[i] = W[i - Nk] ^ temp;
}
}
以上两种情况的相异处在于?/span>Nk?/span>6Ӟ(i-4)?/span>Nk的倍数Ӟ对于W[i-1]先执?/span>SubByteQ再执行EXOR?/span>
上述回合常数定义如下Q?/span>
Rcon[i] = (RC[i],‘
(2) 选择回合金钥(Round Key Selection)
W?/span>i个回合金钥是指在存在回合金钥~冲区的字组W[Nb*i]?/span>W[Nb*(i+1)]Q图C如下:
(本图摘录自参考文?/span>[1])
五、安全性分?/span>
我们针对以下已知的攻L?/span>Rijndael的安全性分析作一要叙qͼ包括差分d?/span>(Differential Cryptanalysis)Q线性攻L(Linear Cryptanalysis)Q^ҎL(The Square Attack)Q内插攻L(Interpolation attacks){攻L式?/span>
(1) 差分d?/span>( Differential Cryptanalysis )
此攻L是一U?/span>Chosen-plaintext attackQ利用大量已知的明文/密文对之间的差异Q据以推出金钥的位倹{在大部分的回合q算?/span>(回合数超q?/span>3)Q若存在过21-n(n指的是区块长?/span>)比例的可预测性的差异Q这个攻L可以推出金钥的位倹{在Rijndael中,已经证明在经q?/span>Rijndael四个回合的运后Q存在不过2-150比例的可预测性差异,在八个回合运中不超q?/span>2-300。详l证明过E,请参照参考文献?/span>
(2) U性攻L( Linear Cryptanalysis )
q是一U?/span>Known-plaintextd法,利用大量搜集到的明文/密文对的相关性,对加密法q行d。明?/span>/密文对的相关性由U性轨q?/span>(Linear trails)所l成Q由于线性轨q的相关pL?/span>Round keys的值有密切关系Q透过相关pL的正负号Q线性攻L可以找出金钥倹{要Ҏq种d法,有一个必要条件就是ɘq种相关pL大于2n/2的线性轨q不存在。在Rijndael中,已经证明出当执行四个回合Ӟ不存在相关系数大?/span>2-75的线性轨q;在执行八个回合时Q其相关pL大于2-150的相关系C不存在。详l证明过E请参照参考文献?/span>
(3) qxd?/span>( The Square attack )
q种d法是一U?/span>chosen- plaintext attackQ而且和字节取?/span>(ByteSub)Q?/span>(MixColumn)时的多项式乘法,金钥的排E?/span>(Key Schedule){运无兟뀂当Rijndael执行6个回合以上时Q此U方式比完全的金钥搜?/span>(exhaustive key search)来的更有效率。关于此U攻L式的详尽描述?/span>Rijndael如何延此种d方式Q请参照参考文献?/span>
(4) 内插d?/span>( Interpolation attacks )
在这U攻L中,d者利用加密的输入及输出配对,建立一些多式。如果加密的lg有一个简z的代数展开式,q且和管理的复杂度结合在一hQ这U攻L便是可行的。基本的d方式是如果攻击者徏立的代数展开式的阶度(degree)很小Q只需要一些加密法的输入及输出配对可以得C数展开式的各项pL。然而,?/span>GF(28)中的取代矩阵(S-box)Q它的展开式ؓQ?/span>63+8fx127+b5x191+01x223+f4x239+25x247+f9x251+09x253+05x254。其余介l,请参照参考文献?/span>
(5)、弱金钥(Weak keys)
关于弱金钥的发生Q基本上是因为加密法的非U性运与实际金钥值有密切关系。而这U问题不存在?/span>Rijndael之中Q因为在Rijndael中,金钥是以EXORq算Q而所有的非线性运都定义在取代矩?/span>(S-box)中。在Rijndael中,寚w钥的选择Q是没有限制的?/span>
六、结论:
以上?/span>Rijndael作一要介l之后,我们?/span>Rijndael的优点与限制作ؓ我们的结论?/span>
(1)?/span>Rijndael有以下优?/span>?/span>
以实作观点而言
1. Rijndael可以实作?/span>Pentium ( Pro ) {计机上,q已相当快的速度处理q算Q而在表格大小与效率之间是可以做取舍的?/span>
2. Rijndael可以实作在智能卡(Smart Card)上,使用量?/span>RAMQ少量的E序代码Q在ROM与效率之间也是可以做取舍的?/span>
3. 在设计上Q回合的转换是可q处理的?/span>
4. 加密法不采用术q算Q不会因Z同处理器架构而有所偏差?/span>
设计单化Q?/span>
1. 设计上不引用其它加密lgQ如S-box?/span>
2. 安全度不建立在一些分析不够明的术q算之上?/span>
3. 加密法紧凑,不易藏入暗门{程序代码?/span>
除此之外Q?/span>Rijndael更允许可变动的区块长度及金钥长度Q其长度可由128位到256位之_所以回合数也是可变动的?/span>
(2)Rijndael的限Ӟ
在解密过E中有以下限?/span>
1. 实作在智慧卡Ӟ解密不如加密来的有效率,解密需要更多的E序代码?/span>cyclesQ但是跟其它法比v来,仍然是快速的?/span>
2. 以Y件而言Q加密和解密使用不同的程序和表格?/span>
3. 以硬件而言Q解密只能重用部分加密的电\?/span>
对关注性能的程序开发h员而言Q一个好的计旉件既是益友,也是良师。计时器既可以作为程序组件帮助程序员_的控制程序进E,又是一件有力的调试武器Q在有经验的E序员手里可以尽快的定E序的性能瓉Q或者对不同的算法作出有说服力的性能比较?/span>
?/span>Windowsq_下,常用的计时器有两U,一U是timeGetTime多媒体计时器Q它可以提供毫秒U的计时。但q个_ֺ对很多应用场合而言q是太粗p了。另一U是QueryPerformanceCount计数器,随系l的不同可以提供微秒U的计数。对于实时图形处理、多媒体数据处理、或者实时系l构造的E序员,善用QueryPerformanceCount/QueryPerformanceFrequency是一基本功?/span>
本文要介l的Q是另一U直接利?/span>Pentium CPU内部旉戌行计时的高精度计时手Dc以下讨Z要得益于?/span>Windows囑Ş~程》一书,W?/span>15-17,有兴的读者可以直接参考该书。关?/span>RDTSC指o的详l讨论,可以参?/span>Intel产品手册。本文仅仅作抛砖之用?/span>
?/span>Intel Pentium以上U别?/span>CPU中,有一个称?/span>“旉戻ITime StampQ?/span>”的部Ӟ它以64位无W号整型数的格式Q记录了?/span>CPU上电以来所l过的时钟周期数。由于目前的CPU主频都非帔RQ因此这个部件可以达到纳U的计时精度。这个精性是上述两种Ҏ所无法比拟的?/span>
?/span>Pentium以上?/span>CPU中,提供了一条机器指?/span>RDTSCQ?/span>Read Time Stamp CounterQ来dq个旉戳的数字Qƈ其保存?/span>EDX:EAX寄存器对中。由?/span>EDX:EAX寄存器对恰好?/span>Win32q_?/span>C++语言保存函数q回值的寄存器,所以我们可以把q条指o看成是一个普通的函数调用。像q样Q?/span>
inline unsigned __int64 GetCycleCount()
{
__asm RDTSC
}
但是不行Q因?/span>RDTSC不被C++的内嵌汇~器直接支持Q所以我们要?/span>_emit伪指令直接嵌入该指o的机器码形式0X0F?/span>0X31Q如下:
inline unsigned __int64 GetCycleCount()
{
__asm _emit 0x0F
__asm _emit 0x31
}
以后在需要计数器的场合,可以像用普通的Win32 API一P调用两次GetCycleCount函数Q比较两个返回值的差,像这P
unsigned long t;
t = (unsigned long)GetCycleCount();
//Do Something time-intensive ...
t -= (unsigned long)GetCycleCount();
?/span>Windows囑Ş~程》第15늼写了一个类Q把q个计数器封装v来。有兴趣的读者可以去参考那个类的代码。作者ؓ了更_的定Ӟ做了一点小的改进Q把执行RDTSC指o的时_通过q箋两次调用GetCycleCount函数计算出来q保存了hQ以后每ơ计时结束后Q都从实际得到的计数中减掉这一段旉Q以得到更准的计时数字。但我个得这一点点改进意义不大。在我的机器上实,q条指o大概花掉了几十到100多个周期Q在Celeron 800MHz的机器上Q这不过是十分之一微秒的时间。对大多数应用来_q点旉完全可以忽略不计Q而对那些实要精到U秒数量U的应用来说Q这个补偿也q于_糙了?/span>
q个Ҏ的优ҎQ?/span>
1.高精度。可以直接达到纳U的计时精度(?/span>1GHz?/span>CPU上每个时钟周期就是一U秒Q,q是其他计时Ҏ所难以企及的?/span>
2.成本低?/span>timeGetTime 函数需要链接多媒体?/span>winmm.libQ?/span>QueryPerformance* 函数ҎMSDN的说明,需要硬件的支持Q虽然我q没有见q不支持的机器)?/span>KERNEL库的支持Q所以二者都只能?/span>Windowsq_下用(关于DOSq_下的高精度计旉题,可以参考《图形程序开发h员指南》,里面有关于控制定时器8253的详l说明)。但RDTSC指o是一?/span>CPU指oQ凡?/span>i386q_?/span>Pentium以上的机器均支持Q甚x有^台的限制Q我怿i386版本UNIX?/span>Linux下这个方法同样适用Q但没有条g试验Q,而且函数调用的开销是最的?/span>
3.h?/span>CPU主频直接对应的速率关系。一个计数相当于1/(CPU主频Hz?/span>)U,q样只要知道?/span>CPU的主频,可以直接计算出时间。这?/span>QueryPerformanceCount不同Q后者需要通过QueryPerformanceFrequency获取当前计数器每U的计数ơ数才能换算成时间?/span>
q个Ҏ的缺ҎQ?/span>
1.现有?/span>C/C++~译器多C直接支持使用RDTSC指oQ需要用直接嵌入机器码的方式~程Q比较麻烦?/span>
2.数据抖动比较厉害。其实对M计量手段而言Q精度和E_性永q是一对矛盾。如果用低精度的timeGetTime来计Ӟ基本上每ơ计时的l果都是相同的;?/span>RDTSC指o每次l果都不一Pl常有几癄至上千的差距。这是这U方法高_ֺ本n固有的矛盾?/span>
关于q个Ҏ计时的最大长度,我们可以单的用下列公式计:
?/span>CPU上电以来的秒?/span> = RDTSCd的周期数 / CPU主频速率Q?/span>HzQ?/span>
64位无W号整数所能表辄最大数字是1.8×10^19Q在我的Celeron 800上可以计时大U?/span>700q_书中说可以在200MHz?/span>Pentium上计?/span>117q_q个数字不知道是怎么得出来的Q与我的计算有出入)。无论如何,我们大可不必兛_溢出的问题?/span>
下面是几个小例子Q简要比较了三种计时Ҏ的用法与_ֺ
//Timer1.cpp 使用?/span>RDTSC指o?/span>Timerc?/span>//KTimercȝ定义可以参见?/span>Windows囑Ş~程?/span>P15
//~译行:CL Timer1.cpp /link USER32.lib
#include <stdio.h>
#include "KTimer.h"
main()
{
unsigned t;
KTimer timer;
timer.Start();
Sleep(1000);
t = timer.Stop();
printf("Lasting Time: %d\n",t);
}
//Timer2.cpp 使用?/span>timeGetTime函数
//需包含<mmsys.h>Q但׃Windows头文仉l复杂的关系
//单包?/span><windows.h>比较hQ)
//~译行:CL timer2.cpp /link winmm.lib
#include <windows.h>
#include <stdio.h>
main()
{
DWORD t1, t2;
t1 = timeGetTime();
Sleep(1000);
t2 = timeGetTime();
printf("Begin Time: %u\n", t1);
printf("End Time: %u\n", t2);
printf("Lasting Time: %u\n",(t2-t1));
}
//Timer3.cpp 使用?/span>QueryPerformanceCounter函数
//~译行:CL timer3.cpp /link KERNEl32.lib
#include <windows.h>
#include <stdio.h>
main()
{
LARGE_INTEGER t1, t2, tc;
QueryPerformanceFrequency(&tc);
printf("Frequency: %u\n", tc.QuadPart);
QueryPerformanceCounter(&t1);
Sleep(1000);
QueryPerformanceCounter(&t2);
printf("Begin Time: %u\n", t1.QuadPart);
printf("End Time: %u\n", t2.QuadPart);
printf("Lasting Time: %u\n",( t2.QuadPart- t1.QuadPart));
}
////////////////////////////////////////////////
//以上三个CZE序都是试1U钟休眠所耗费的时?/span>
源码下蝲: http://www.ppcn.net/upload
P2P之UDPIKNAT的原理与实现(shootingstar
文章说明:
关于UDPIKNAT的中文资料在|络上是很少的,仅有<
再次感谢shootingstars|友的早期A? 表示谢意?
NAT(The IP Network Address Translator) 的概念和意义是什?
NAT, 中文译为网l地址转换。具体的详细信息可以讉KRFC 1631 - http://www.faqs.org/rfcs
要想完全明白NAT 的作用,我们必须理解IP地址的两大分c,一cLU有IP地址
内网IP地址: 是指使用A/B/CcM的私有地址, 分配的IP地址在全球不惧有唯一性,也因此无法被其它外网L直接
NAT 最初的目的是ؓ使用内网IP地址的计机提供通过数几台h公网
图一: NAT 实现了私有IP的计机分n几个公网IP地址讉KInternet
随着|络的普及,IPv4的局限性暴露出来。公|IP地址成ؓ一U?wbr>E~的资源Q此时NAT 的功能局限也暴露出来Q同一个公|的IP地址Q某个时间只能由一?wbr>U有IP地址的计机使用。于是NAPT(The IP Network Address/Port Translator)应运而生QNAPT实现了多台私有IP地址
NAPT 负责某些内|IP地址的计机向外部网l发出的TCP
图二: NAPT 实现了私有IP的计机分n一个公|IP地址讉KInternet
在我们的工作和生zM, NAPT的作用随处可见,l大部分公司的网l架?wbr>Q都是通过1至N台支持NAPT的\由器来实现公司的所有计机q?wbr>接外部的Internet|络的。包括本人在写这文章的时?wbr>Q也是在家中使用一台IBMW记本通过一台宽带连接的台式机来讉K
NAPT(The IP Network Address/Port Translator) Zȝ了P2P软g的应?
通过NAPT 上网的特点决定了只能由NAPT内的计算Z动向NAPT外部的主
NAT(The IP Network Address Translator) q行UDPIK的原理是什?
TCP/IP传输时主要用到TCP和UDP协议。TCP协议是可?wbr>的,面向q接的传输协议。UDP是不可靠的,无连接的协议
图三: NAPT 是如何将U有IP地址的UDP数据包与公网Lq行透明传输的?
UDP协议包经NAPT透明传输的说?
NAPT为每一个Session分配一个NAPT自己的端口号
囑֛: NAPT 内部发出的UDP协议包的源地址和源端口改变传输l公|IPL
图五: NAPT 收到的公网IPLq回的UDP协议包的目的地址和目的端口改?wbr>传输l内|IP计算机现在我们大概明白了NAPT如何实现内网计算
A. 源地址(内网IP地址)不同Q忽略其它因? 在NAPT上肯定对应不同的Session B. 源地址(内网IP地址)相同Q源端口不同Q忽略其它的因素
D的情冉|式我们关心和要讨论的问题。依据目的地址
Symmetric NAPT: 对于到同一个IP地址QQ意端口的q接分配使用同一个Sessio
囑օ: Symmetric 的英文意思是对称。多个端口对应多个主机,q的,对称?
Cone NAPT: 对于到同一个IP地址QQ意端口的q接分配使用同一个Sessio
图七: Cone 的英文意思是锥。一个端口对应多个主机,是不是像个锥?
现在l大多数的NAPT属于后者,即Cone NAT。本人在试的过E中Q只好用了一台日本的Symmetr
下面我们再来分析一下NAPT 工作时的一些数据结构,在这里我们将真正说明UDP可以IKCon
Symmetric NAPT 工作时的端口映射数据l构如下:
内网信息?
[NAPT 分配端口] [ 内网IP地址 ] [ 内网端口 ] [ 外网IP地址 ] [ SessionTime 开始时?]
PRIMARY KEY( [NAPT 分配端口] ) -> 表示依据[NAPT 分配端口]建立主键Q必d一且徏立烦引,加快查找. UNIQUE( [ 内网IP地址 ], [ 内网端口 ] ) -> 表示q两个字D联合v来不能重? UNIQUE( [ 内网IP地址 ], [ 内网端口 ], [ 外网IP地址 ] ) -> 表示q三个字D联合v来不能重?
映射?
[NAPT 分配端口] [ 外网端口 ]
UNIQUE( [NAPT 分配端口], [ 外网端口 ] ) -> 表示q两个字D联合v来不能重?
Cone NAPT 工作时的端口映射数据l构如下:
内网信息?
[NAPT 分配端口] [ 内网IP地址 ] [ 内网端口 ] [ SessionTime 开始时?]
PRIMARY KEY( [NAPT 分配端口] ) -> 表示依据[NAPT 分配端口]建立主键Q必d一且徏立烦引,加快查找. UNIQUE( [ 内网IP地址 ], [ 内网端口 ] ) -> 表示q两个字D联合v来不能重?
外网信息?
[ wid 主键标识 ] [ 外网IP地址 ] [ 外网端口 ]
PRIMARY KEY( [ wid 主键标识 ] ) -> 表示依据[ wid 主键标识 ]建立主键Q必d一且徏立烦引,加快查找. UNIQUE( [ 外网IP地址 ], [ 外网端口 ] ) -> 表示q两个字D联合v来不能重?
映射? 实现一对多Q的
[NAPT 分配端口] [ wid 主键标识 ]
UNIQUE( [NAPT 分配端口], [ wid 主键标识 ] ) -> 表示q两个字D联合v来不能重? UNIQUE( [ wid 主键标识 ] ) -> 标识此字D不能重?
看完了上面的数据l构是更明白了还是更晕了Q?呵呵! 多想一会儿׃明白了。通过NAT,内网计算机向外q结是很
c 是一台在NAPT后面的内|计机Qs是一台有外网IP地址的计?wbr>机。c d?s 发vq接hQNAPT依据上面描述的规则在自己的数据结构中记录
c[192.168.0.6:1827] <-> [priv ip: 192.168.0.1]NAPT[pub ip: 61.51.99.86:9881] <-> s[61.51.76.102:8098]
由此可见Q一台外|IP地址的计机惛_NAPT后面的内|计机
现在我们再来分析一下我们最兛_的两个NAPT后面的内|计机?wbr>何实现直接通讯? 两者都无法d发出q接hQ谁也不知道Ҏ的NAPT的公|IP
我们假设两个内网计算机分别ؓA和BQ对应的NAPT分别为AN?
NAPT(The IP Network Address/Port Translator) q行UDPIK的具体情况分析!
首先明确的将NAPT讑֤按照上面的说明分? Symmetric NAPT ?Cone NAPT, Cone NAPT 是我们需要的。Win9x/2K/XP/2003 自带的NAPT也ؓCone NAPT?
W一U情? 双方都是Symmetric NAPT:
此情况应l不存在什么问题,肯定是不支持UDPIK?
W二U情? 双方都是Cone NAPT:
此情冉|我们需要的Q可以进行UDPIK?
W三U情? 一个是Symmetric NAPT, 一个是Cone NAPT:
此情冉|较复杂,但我们按照上面的描述和数据机构进行一下分析也?wbr>Ҏ׃明白? 分析如下,
假设: A -> Symmetric NAT, B -> Cone NAT
1. A 惌?B, A 从服务器那儿获取?B 的NAT地址和映端? A 通知服务器,服务器告?B A的NAT地址和映端? B ?A 发vq接QA 肯定无法接收到。此?A ?B 发vq接Q?A 对应的NAT建立了一个新的SessionQ分配了一个新的映端
2. B 惌?A, B 从服务器那儿获取?A 的NAT地址和映端? B 通知服务? 服务器告?A B的NAT地址和映端?A ?B 发vq接, A 对应的NAT建立了一个新的SessionQ分配了一个新的映端
Ҏ以上分析Q只有当q接的两端的NAT都ؓCone NAT的情况下Q才能进行UDP的内|穿透互联?
NAPT(The IP Network Address/Port Translator) q行UDPIK如何进行现实的验证和分?
需要的|络l构如下:
三个NAT后面的内|机器,两个外网服务器。其中两台Cone NAPTQ一?Symmetric NAPT?
验证Ҏ:
可以使用本程序提供的源码Q编译,然后分别q行服务器程序和客户?wbr>。修改过后的源码增加了客L之间直接通过IP地址和端口发送消?wbr>的命令,利用此命令,你可以手动的验证NAPT的穿透情?wbr>。ؓ了方便操作,推荐你用一个远E登陆YӞ可以直接在一台机?wbr>上操作所有的相关的计机Q这样很方便Q一个h可以完成所有的?wbr>作了。呵呵,本h是q么完成的。欢q有兴趣和经验的朋友来信批评