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加密或解密,得到相應(yīng)的密文或明文。假設(shè)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對應(yīng)KL(左8字節(jié)),K2對應(yīng)KR(右8字節(jié)),K3對應(yīng)KL(左8字節(jié))。
由于DES加解密算法是每8個字節(jié)作為一個加解密數(shù)據(jù)塊,因此在實現(xiàn)該算法時,需要對數(shù)據(jù)進行分塊和補位(即最后不足8字節(jié)時,要補足8字節(jié))。Java本身提供的API中NoPadding,Zeros填充和PKCS5Padding。假設(shè)我們要對9個字節(jié)長度的數(shù)據(jù)進行加密,則其對應(yīng)的填充說明如下:
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的具體算法過程很復(fù)雜,實話說我也不懂,我只能借用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];
[key 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(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];
?。踜ey appendData:key1];
[key 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;
}
Java使用3DES加密解密的流程
?、賯魅牍餐s定的密鑰(keyBytes)以及算法(Algorithm),來構(gòu)建SecretKey密鑰對象
SecretKey deskey = new SecretKeySpec(keyBytes, Algorithm);
?、诟鶕?jù)算法實例化Cipher對象。它負(fù)責(zé)加密/解密
Cipher c1 = Cipher.getInstance(Algorithm);
?、蹅魅爰用?解密模式以及SecretKey密鑰對象,實例化Cipher對象
c1.init(Cipher.ENCRYPT_MODE, deskey);
?、軅魅胱止?jié)數(shù)組,調(diào)用Cipher.doFinal()方法,實現(xiàn)加密/解密,并返回一個byte字節(jié)數(shù)組
c1.doFinal(src);
3DES案例
—SecretUtils.java(3DES加密解密的工具類)—
package my3des;
import java.io.UnsupportedEncodingException;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
/**
* SecretUtils {3DES加密解密的工具類 }
* @author William
* @date 2013-04-19
*/
public class SecretUtils {
//定義加密算法,有DES、DESede(即3DES)、Blowfish
private static final String Algorithm = “DESede”;
private static final String PASSWORD_CRYPT_KEY = “2012PinganVitality075522628888ForShenZhenBelter075561869839”;
/**
* 加密方法
* @param src 源數(shù)據(jù)的字節(jié)數(shù)組
* @return
*/
public static byte[] encryptMode(byte[] src) {
try {
SecretKey deskey = new SecretKeySpec(build3DesKey(PASSWORD_CRYPT_KEY), Algorithm); //生成密鑰
Cipher c1 = Cipher.getInstance(Algorithm); //實例化負(fù)責(zé)加密/解密的Cipher工具類
c1.init(Cipher.ENCRYPT_MODE, deskey); //初始化為加密模式
return c1.doFinal(src);
} catch (java.security.NoSuchAlgorithmException e1) {
e1.printStackTrace();
} catch (javax.crypto.NoSuchPaddingException e2) {
e2.printStackTrace();
} catch (java.lang.Exception e3) {
e3.printStackTrace();
}
return null;
}
/**
* 解密函數(shù)
* @param src 密文的字節(jié)數(shù)組
* @return
*/
public static byte[] decryptMode(byte[] src) {
try {
SecretKey deskey = new SecretKeySpec(build3DesKey(PASSWORD_CRYPT_KEY), Algorithm);
Cipher c1 = Cipher.getInstance(Algorithm);
c1.init(Cipher.DECRYPT_MODE, deskey); //初始化為解密模式
return c1.doFinal(src);
} catch (java.security.NoSuchAlgorithmException e1) {
e1.printStackTrace();
} catch (javax.crypto.NoSuchPaddingException e2) {
e2.printStackTrace();
} catch (java.lang.Exception e3) {
e3.printStackTrace();
}
return null;
}
/*
* 根據(jù)字符串生成密鑰字節(jié)數(shù)組
* @param keyStr 密鑰字符串
* @return
* @throws UnsupportedEncodingException
*/
public static byte[] build3DesKey(String keyStr) throws UnsupportedEncodingException{
byte[] key = new byte[24]; //聲明一個24位的字節(jié)數(shù)組,默認(rèn)里面都是0
byte[] temp = keyStr.getBytes(“UTF-8”); //將字符串轉(zhuǎn)成字節(jié)數(shù)組
/*
77 * 執(zhí)行數(shù)組拷貝
* System.arraycopy(源數(shù)組,從源數(shù)組哪里開始拷貝,目標(biāo)數(shù)組,拷貝多少位)
*/
if(key.length 》 temp.length){
//如果temp不夠24位,則拷貝temp數(shù)組整個長度的內(nèi)容到key數(shù)組中
System.arraycopy(temp, 0, key, 0, temp.length);
}else{
//如果temp大于24位,則拷貝temp數(shù)組24個長度的內(nèi)容到key數(shù)組中
System.arraycopy(temp, 0, key, 0, key.length);
}
return key;
}
}
—Main.java(測試類)—
package my3des;
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
String msg = “3DES加密解密案例”;
System.out.println(“【加密前】:” + msg);
//加密
byte[] secretArr = SecretUtils.encryptMode(msg.getBytes());
System.out.println(“【加密后】:” + new String(secretArr));
//解密
byte[] myMsgArr = SecretUtils.decryptMode(secretArr);
System.out.println(“【解密后】:” + new String(myMsgArr));
}
}
評論
查看更多