3DES,也稱為3DESede或TripleDES,是三重數(shù)據(jù)加密,且可以逆推的一種算法方案。1975年美國IBM公司成功研究并發(fā)布了DES加密算法,但DES密碼長度容易被暴力破解,通過對DES算法進行改進,針對每個數(shù)據(jù)塊進行三次DES加密,也就是3DES加密算法。但由于3DES的算法是公開的,所以算法本身沒什么秘密可言,主要依靠唯一密鑰來確保數(shù)據(jù)加密解密的安全。
有人可能會問,那3DES到底安不安全呢?!目前為止,還沒有人能破解3DES,所以你要是能破解它,都足以震驚整個信息安全界了。
3DES加密算法簡析3DES加密算法并非什么新的加密算法,而是DES算法的另一種模式。是現(xiàn)在比較常用的一種對稱加密算法,比起DES來說安全性更高。該算法的加解密過程分別是對明文/密文數(shù)據(jù)進行三次DES加密或解密,得到相應的密文或明文。假設EK()和DK()分別表示DES的加密和解密函數(shù),P表示明文,C表示密文,那么加解密的公式如下:
加密:C = EK3( DK2( EK1(P) ) ) 即對明文數(shù)據(jù)進行,加密 --》 解密 --》 加密的過程,最后得到密文數(shù)據(jù)
解密:P = DK1( EK2( DK3(C) ) ) 即對密文數(shù)據(jù)進行,解密 --》 加密 --》 解密的過程,最后得到明文數(shù)據(jù)
其中:K1表示3DES中第一個8字節(jié)密鑰,K2表示第二個8字節(jié)密鑰,K3表示第三個8字節(jié)密鑰,通常情況下,3DES的密鑰為雙倍長密鑰(若不知道雙倍長,可參考博主的密鑰分算算法文章中的解釋),即K1對應KL(左8字節(jié)),K2對應KR(右8字節(jié)),K3對應KL(左8字節(jié))。
由于DES加解密算法是每8個字節(jié)作為一個加解密數(shù)據(jù)塊,因此在實現(xiàn)該算法時,需要對數(shù)據(jù)進行分塊和補位(即最后不足8字節(jié)時,要補足8字節(jié))。Java本身提供的API中NoPadding,Zeros填充和PKCS5Padding。假設我們要對9個字節(jié)長度的數(shù)據(jù)進行加密,則其對應的填充說明如下:
ZerosPadding
無數(shù)據(jù)的字節(jié)全部被填充為0
第一塊:F0 F1 F2 F3 F4 F5 F6 F7
第二塊:F8 0 0 0 0 0 0 0
PKCS5Padding
每個被填充的字節(jié)都記錄了被填充的長度
第一塊:F0 F1 F2 F3 F4 F5 F6 F7
第二塊:F8 07 07 07 07 07 07 07
DES的具體算法過程很復雜,實話說我也不懂,我只能借用Android和iOS里面自帶的API去實現(xiàn)3DES的過程,其具體代碼如下:
Android代碼
?。踦lain] view plain copypublic byte[] triDesEncrypt(byte[] desKey, byte[] desData, int flag) {//flag == 1為加密,flag == 0為解密
byte[] keyFirst8 = new byte[8];
byte[] keySecond8 = new byte[8];
if (desKey.length 》 8) {
for (int i = 0; i 《 8; i++) {
keyFirst8[i] = desKey[i];
}
} else {
return null;
}
if (desKey.length 《 16) {
for (int i = 0; i 《 desKey.length - 8; i++) {
keySecond8[i] = desKey[i + 8];
}
} else {
for (int i = 0; i 《 8; i++) {
keySecond8[i] = desKey[i + 8];
}
}
byte[] tmpKey = new byte[8];
byte[] tmpData = new byte[8];
arrayCopy(keyFirst8, 0, tmpKey, 0, 8);
arrayCopy(desData, 0, tmpData, 0, 8);
int mode = flag;
byte[] result = unitDes(tmpKey, tmpData, mode);
arrayCopy(keySecond8, 0, tmpKey, 0, 8);
arrayCopy(result, 0, tmpData, 0, 8);
mode = (mode == 1) ? 0 : 1;
result = unitDes(tmpKey, tmpData, mode);
arrayCopy(keyFirst8, 0, tmpKey, 0, 8);
arrayCopy(result, 0, tmpData, 0, 8);
mode = (mode == 1) ? 0 : 1;
result = unitDes(tmpKey, tmpData, mode);
return result;
}
iOS代碼
?。踦lain] view plain copy+ (NSData *)encryptWithDataKey:(NSData *)src key1:(NSData *)key1 key2:(NSData *)key2 key3:(NSData *)key3
{
if (src == nil || [src length] == 0 ||
key1 == nil || [key1 length] == 0 ||
key2 == nil || [key2 length] == 0 ||
key3 == nil || [key3 length] == 0) {
return nil;
}
const void *vplainText;
size_t plainTextBufferSize;
plainTextBufferSize = [src length];
vplainText = [src bytes];
CCCryptorStatus ccStatus;
uint8_t *bufferPtr = NULL;
size_t bufferPtrSize = 0;
size_t movedBytes = 0;
bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
bufferPtr = malloc(bufferPtrSize * sizeof(uint8_t));
memset((void *)bufferPtr, 0x00, bufferPtrSize);
NSMutableData *key = [NSMutableData data];
?。踜ey appendData:key1];
?。踜ey appendData:key2];
[key appendData:key3];
NSString *initVec = @“01234567”;
const void *vKey = [key bytes];
const void *vinitVec = (const void *)[initVec UTF8String];
uint8_t iv[kCCBlockSize3DES];
memset((void *)iv, 0x00, (size_t)sizeof(iv));
ccStatus = CCCrypt(kCCEncrypt, kCCAlgorithm3DES, kCCOpTIonPKCS7Padding | kCCOpTIonECBMode, vKey, kCCKeySize3DES, vinitVec, vplainText, plainTextBufferSize, (void *)bufferPtr, bufferPtrSize, &movedBytes);
if (ccStatus != kCCSuccess) {
free(bufferPtr);
return nil;
}
NSData *result = [NSData dataWithBytes:bufferPtr length:movedBytes];
free(bufferPtr);
return result;
}
+ (NSData *)decryptWithDataKey:(NSData *)src key1:(NSData *)key1 key2:(NSData *)key2 key3:(NSData *)key3
{
if (src == nil || [src length] == 0 ||
key1 == nil || [key1 length] == 0 ||
key2 == nil || [key2 length] == 0 ||
key3 == nil || [key3 length] == 0) {
return nil;
}
const void *vplainText;
size_t plainTextBufferSize;
plainTextBufferSize = [src length];
vplainText = [src bytes];
CCCryptorStatus ccStatus;
uint8_t *bufferPtr = NULL;
size_t bufferPtrSize = 0;
size_t movedBytes = 0;
bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
bufferPtr = malloc(bufferPtrSize * sizeof(uint8_t));
memset((void *)bufferPtr, 0x00, bufferPtrSize);
NSMutableData *key = [NSMutableData data];
[key appendData:key1];
?。踜ey appendData:key2];
?。踜ey appendData:key3];
NSString *initVec = @“01234567”;
const void *vkey = [key bytes];
const void *vinitVec = (const void *)[initVec UTF8String];
uint8_t iv[kCCBlockSize3DES];
memset((void *)iv, 0x00, (size_t)sizeof(iv));
ccStatus = CCCrypt(kCCDecrypt, kCCAlgorithm3DES, kCCOpTIonPKCS7Padding | kCCOpTIonECBMode, vkey, kCCKeySize3DES, vinitVec, vplainText, plainTextBufferSize, (void *)bufferPtr, bufferPtrSize, &movedBytes);
if (ccStatus != kCCSuccess) {
free(bufferPtr);
return nil;
}
NSData *result = [NSData dataWithBytes:bufferPtr length:movedBytes];
free(bufferPtr);
return result;
}