AES(高级加密标准Advanced Encryption Standard)
2000年10月,NIST(美国国家标准和技术协会)宣布通过从15种侯选算法中选出的一项新的密匙加密标准。新的标准将会代替密匙长度变的太短的旧的DES算法。Rijndael被选中成为将来的AES。Rijndael这个名字是从它的两个发明者Rijmen和Daemen的名字得来的。
这个加密体系据说是一种分组加密方法,因为信息的内容是以128位长度的分组为加密单元的。加密密匙长度有128,192或256位多种选择。正象你所知的那样,DES加密的分组长度是64比特,而密匙长度只有64比特。三重DES加密的分组长度通常是64比特,而密匙长度上112比特。
图一描述了AES的操作模式。首先密匙K0和待加密信息按位相与。然后所有要加密的分组都用一个函数F进行迭代计算,计算用的子密匙是由一个密匙扩展函数产生的,初始的密匙是主密匙。
对于AES 函数F要迭代10次。
图2描述的是加密过程中函数F是如何被迭代的。一个128位的分组转换成16个字节,作为下面处理的输入。首先,每一个字节分别经过替换函数S的处理,然后,用第二个置换函数P对16个字节进行处理。然后这个结果就和匙扩展函数产生的子匙进行位与。
匙Ki是用匙扩展函数从第K(i-1)轮的子匙和第K0的密匙得到的。图三描述了匙扩展函数。16个字节的被分成4组,每组4个字节,来进行处理。最后的一组的4个字节由替换函数S(这个S和用F函数进行迭代处理时的S是一样的)来进行替换处理。最初的4个字节的结果和α系数相加,这个系数是与轮数相关的,它是预先定义的。最后,为了得到Ki,把得到的4个字节的结果和K(i-1)匙的最初4个字节按位相加,然后得到的结果又和K(i-1)匙的下面的4个字节按位相加,如此类推。
好了,现在我们简单地看看替换函数是怎么得到的,然后看看ai 常数有什么作用。为了简单的理由,一个字节应该是256个元素集(称为有限域)的一个元素,对于这些元素只包含一些简单的操作(例如加法,乘法,反转)。事实上,前面提到的替换函数S在那个有限域里的反转。置换函数S被定义为一个很简单的操作,以便能简单的实现。ai 系数是和指数I(有限域的元素)成正比的。这些考虑,使得AES实现起来非常有效。
因为AES仅仅在基于简单的位操作运算,这有两个主要的优点:
即使是纯粹的软件实现,AES也是很快的。例如,用C++在奔腾200的电脑上实现的AES的加密速度可达到70M位/秒;
AES并不依赖于S-Box的选择(根据NSA, DES里的S-Boxes可能包含后门),对分析算法抗击差分密码分析及线性密码分析具有能力。
+(NSString *)AES128Encrypt:(NSString *)plainText
{
char keyPtr[kCCKeySizeAES128+1];
memset(keyPtr, 0, sizeof(keyPtr));
[gkey getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
char ivPtr[kCCBlockSizeAES128+1];
memset(ivPtr, 0, sizeof(ivPtr));
[gIv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
NSData* data = [plainText dataUsingEncoding:NSUTF8StringEncoding];
NSUInteger dataLength = [data length];
int diff = kCCKeySizeAES128 - (dataLength % kCCKeySizeAES128);
int newSize = 0;
if(diff > 0)
{
newSize = dataLength + diff;
}
char dataPtr[newSize];
memcpy(dataPtr, [data bytes], [data length]);
for(int i = 0; i < diff; i++)
{
dataPtr[i + dataLength] = 0x00;
}
size_t bufferSize = newSize + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
memset(buffer, 0, bufferSize);
size_t numBytesCrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmAES128,
0x0000, //No padding
keyPtr,
kCCKeySizeAES128,
ivPtr,
dataPtr,
sizeof(dataPtr),
buffer,
bufferSize,
&numBytesCrypted);
if (cryptStatus == kCCSuccess) {
NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesCrypted];
return [GTMBase64 stringByEncodingData:resultData];
}
free(buffer);
return nil;
}
+(NSString *)AES128Decrypt:(NSString *)encryptText
{
char keyPtr[kCCKeySizeAES128 + 1];
memset(keyPtr, 0, sizeof(keyPtr));
[gkey getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
char ivPtr[kCCBlockSizeAES128 + 1];
memset(ivPtr, 0, sizeof(ivPtr));
[gIv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
NSData *data = [GTMBase64 decodeData:[encryptText dataUsingEncoding:NSUTF8StringEncoding]];
NSUInteger dataLength = [data length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesCrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
kCCAlgorithmAES128,
0x0000,
keyPtr,
kCCBlockSizeAES128,
ivPtr,
[data bytes],
dataLength,
buffer,
bufferSize,
&numBytesCrypted);
if (cryptStatus == kCCSuccess) {
NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesCrypted];
return [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
}
free(buffer);
return nil;
}