但是移植过程中发现一些问题,这里我把自己走过的弯路分享出来!
Note:下文中提到的 identifier "z","L"均来自算法官方源代码的上下文,这里不作详细说明。
1. EEA算法过程,官方代码没有错误,但是在小端平台不兼容,因此要适配改善。加密最后用Keystream对plainText进行异或加密时,
由于z[i]是大端存储的码流,而plainText本来是unsigned char 类型的码流,但转换为unsigned int类型的M[1]后,无疑就会在小端平台发生大小端颠倒的问题
因此我们应该作一个小的改动,在源代码的EEA3函数最后的for循环里,在C[i] = M[i] ^ z[i]前面增加一行代码:z[i] = ntohl(z[i]);
或者我们采用以字节为最小单位来进行异或操作,change the EEA3()'s parameter "u32 *M" into "u8 *M" type. 如下改进后的for循环(另增加一个switch语句):
- u32 tempLen = LENGTH&0xFFFFFFFC;
- u32 zIndex = 0;
- for(i = 0; i<tempLen; i+=4)
- {
- zIndex = i/4;
- M[i] ^= z[zIndex]>>24;
- M[i+1] ^= z[zIndex]>>16;
- M[i+2] ^= z[zIndex]>>8;
- M[i+3] ^= z[zIndex];
- }
- switch(LENGHTH)&0x03
- {
- case 3:
- M[i+2] ^= z[zIndex+1]>>8;
- case 2:
- M[i+1] ^= z[zIndex+1]>>16;
- case 1:
- M[i] ^= z[zIndex+1]>>24;
- default:
- break;
- }
u32 tempLen = LENGTH&0xFFFFFFFC;
u32 zIndex = 0;
for(i = 0; i<tempLen; i+=4)
{
zIndex = i/4;
M[i] ^= z[zIndex]>>24;
M[i+1] ^= z[zIndex]>>16;
M[i+2] ^= z[zIndex]>>8;
M[i+3] ^= z[zIndex];
}
switch(LENGHTH)&0x03
{
case 3:
M[i+2] ^= z[zIndex+1]>>8;
case 2:
M[i+1] ^= z[zIndex+1]>>16;
case 1:
M[i] ^= z[zIndex+1]>>24;
default:
break;
}
2. 官方源代码的EIA3也是有问题的,首先要把GET_BIT()函数里增加对大小端平台的兼容性适配,改为按字节操作,接口类型也改了
- u8 GET_BIT(u8 *DATA, u32 i)
- {
- return (DATA[i/8]) & (1<<(7-(i%8)))) ? 1 : 0;
- }
u8 GET_BIT(u8 *DATA, u32 i)
{
return (DATA[i/8]) & (1<<(7-(i%8)))) ? 1 : 0;
}
在EIA3()函数的最后,源代码是:*MAC = T ^ GET_WORD(z,LENGHTH+32);
这是错误的,参考EEA3_EIA3_specifcation_v1_6.pdf 的4.5小节,最后计算MAC时是 T^Z(32*(L-1)),其实就是异或上 Z的最后四字节。将源代码更正为下面任意一行代码均能通过测试数据的测试。
- *MAC = T ^ GET_WORD(z,(LENGHTH+63)&0xFFFFFFE0);
- *MAC = T ^ z[L-1];/* 这个效率更高 */