java加解密之DES多種使用方式

最近逆向分析中,常常遇到加解密的內容,接觸得比較多的加解密算法一般有對稱的DES和AES,非對稱的RSA,單向的MD5等。

這裏就DES的使用研究進行一個隨筆記錄,並不會說其實現原理,原理可以自行百度。

DES作爲56位祕鑰加密目前已經被容易破解了,儘管如此,在一些簡單而又不是很敏感的數據加密中還是有它的身影。

在Android逆向分析中,在被混淆的代碼裏,往往你能看到一個方法a的參數是byte[ ],返回值也是byte[ ],而且在裏面又有“DES”的字符串,如果不繼續分析其內容而直接猜測的話,這個方法a 究竟是DES的什麼工作模式?不妨猜測一下:

首先,加密還是解密?用的是 Cypher.ENCRYPT 還是 Cypher.DECRYPT? x 2

接着,祕鑰的生成方式?用的是SecretKeyFactory 還是 KeyGenerator 抑或 直接用 SecretKeySpec ? x3

最後,塊加密的模式? ECB,CBC,OFB,CFB等?是否有填充操作? x4+

x2x3x4+=24+

24種以上的結果~

雖然逆向分析中只需要知道其用法即可,細節的研究對其分析並不會有多大的效率上的幫助,但我還是去折騰了一番~


----------------------開始分割線-----------------------

這裏,我先貼出一種比較常用的調用方式:DES     使用SecretKeyFactory 的祕鑰     選擇CBC模式     進行加解密。

public class DESCryptography {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		String content="aaaaaaaabbbbbbbbaaaaaaaa";
		String key="01234567";
	
		System.out.println("加密前:"+byteToHexString(content.getBytes()));
		byte[] encrypted=DES_CBC_Encrypt(content.getBytes(), key.getBytes());
		System.out.println("加密後:"+byteToHexString(encrypted));
		byte[] decrypted=DES_CBC_Decrypt(encrypted, key.getBytes());
		System.out.println("解密後:"+byteToHexString(decrypted));
 	}

	public static byte[] DES_CBC_Encrypt(byte[] content, byte[] keyBytes){		
		try {
			DESKeySpec keySpec=new DESKeySpec(keyBytes);
			SecretKeyFactory keyFactory=SecretKeyFactory.getInstance("DES");			
			SecretKey key=keyFactory.generateSecret(keySpec);		
			
			Cipher cipher=Cipher.getInstance("DES/CBC/PKCS5Padding");
			cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(keySpec.getKey()));			
			byte[] result=cipher.doFinal(content);
			return result;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			System.out.println("exception:"+e.toString());
		}
		return null;
	}
	
	public static byte[] DES_CBC_Decrypt(byte[] content, byte[] keyBytes){		
		try {
			DESKeySpec keySpec=new DESKeySpec(keyBytes);
			SecretKeyFactory keyFactory=SecretKeyFactory.getInstance("DES");
			SecretKey key=keyFactory.generateSecret(keySpec);
			
			Cipher cipher=Cipher.getInstance("DES/CBC/PKCS5Padding");
			cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(keyBytes));
			byte[] result=cipher.doFinal(content);
			return result;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			System.out.println("exception:"+e.toString());
		}
		return null;
	}
	
	public static String byteToHexString(byte[] bytes) {
        StringBuffer sb = new StringBuffer(bytes.length);
        String sTemp;
        for (int i = 0; i < bytes.length; i++) {
            sTemp = Integer.toHexString(0xFF & bytes[i]);
            if (sTemp.length() < 2)
                sb.append(0);
            sb.append(sTemp.toUpperCase());
        }
        return sb.toString();
    }
	  
	 private static byte toByte(char c) {
	    byte b = (byte) "0123456789ABCDEF".indexOf(c);
	    return b;
	 }
}

運行結果:



這是一個標準的使用方法~

-----------------------結束分割線----------------------------


若是這麼簡單就好了,對於有強迫症的我,感覺沒把它完全弄清楚,感覺就是不爽~~~

然而,我還是講一下其它方法的研究吧。

1、  加密還是解密。

只需要在Cypher.init初始化時設置Mode即可,即Cypher.ENCRYPT 或 Cypher.DECRYPT。

2、  祕鑰的產生。

這個有點噁心, 我研究了一下 KeyGenerator, KeyPairGenerator,KeyFactory,SecretKeyFactory這四個類,是有區別的。

根據 Oracle 的 Standard Algorithm Name Documentation 提供的說明:

KeyGenerator和SecretKeyFactory,都是javax.crypto包的,生成的key主要是提供給AES,DES,3DES,MD5,SHA1等 對稱 和 單向 加密算法

KeyPairGenerator和KeyFactory,都是java.security包的,生成的key主要是提供給DSA,RSA, EC等 非對稱加密算法

在這裏,因爲是DES算法,所以我主要是研究上面那兩個類,那麼,Generator 和 Factory 有什麼區別呢?

額。。。鑑於水平有限,只能說,兩者都是對key進行加工,生成新的key,只是生成的方法不一樣,生成的結果也不一樣。

順便一提,還有一個同時實現了Key和KeySpec接口的SecretKeySpec類,該類可以直接用keyBytes生成原始的key,即沒有加工過,不同上面的Factory和Generator。

我將3種生成key的方法和結果貼出來:

	public static void printKey(byte[] keyBytes){
		try{
			//第一種,Factory
			DESKeySpec keySpec=new DESKeySpec(keyBytes);
			SecretKeyFactory keyFactory=SecretKeyFactory.getInstance("DES");			
			SecretKey key1=keyFactory.generateSecret(keySpec);	
			
			//第二種, Generator
			KeyGenerator keyGenerator=KeyGenerator.getInstance("DES");
			keyGenerator.init(56, new SecureRandom(keyBytes));//key爲8個字節,實際用了56位; 後面隨機數用key作爲種子seed生成
			SecretKey key2=keyGenerator.generateKey();
			
			//第三種, SecretKeySpec
			SecretKey key3=new SecretKeySpec(keyBytes, "DES");//SecretKeySpec類同時實現了Key和KeySpec接口
			
			//打印
			System.out.println("key1:"+byteToHexString(key1.getEncoded()));
			System.out.println("key2:"+byteToHexString(key2.getEncoded()));
			System.out.println("key3:"+byteToHexString(key3.getEncoded()));
			
		}catch(Exception e){
			System.out.println(e.toString());
		}	
	}
打印結果:



就結果看來,key3是原始的,沒有加工過;key1是經過Factory生成的,只是將其稍微加工了一下,加了一些置換操作;而key2是經過Generator通過SecureRandom生成的,所以大幅度變形。

3、塊加密的模式以及數據填充。

看下面的一行代碼:

Cipher cipher=Cipher.getInstance("DES/CBC/NoPadding");
Cipher加密器初始化需要一個字符串,字符串裏提供了三種設置。
一是,加解密算法;二是,加解密模式;三是,是否需要填充。

常見的模式有四種:

ECB(電碼本模式),CBC(加密塊鏈模式),OFB(輸出反饋模式),CFB(加密反饋模式),這些模式的原理在網上都有很多,這裏不講。

ECB模式簡單,缺點是塊加密的內容容易重複,會被統計分析攻擊;

CBC,  OFB,  CFB三個模式,都是根據前面加密塊的內容,對key進行新一輪處理後再,再對下一數據塊進行處理,如此類推下去,這樣一來,加密的強度也有所增強。他們都需要用到初始化向量IV,英文大概是Initialization Vector的縮寫吧。

填充:

對於加密,因爲DES是塊加密,數據長度必須是8的倍數,然而實際上加密前的明文getBytes()後基本不會恰好是8的倍數,所以一般需要進行填充,填充的規則這裏不說,想知道的百度吧,反正這個只需要設置參數 PKCS5Padding ,JDK就幫你填充了,若不填充,且數據長度不是8倍數,則會拋異常;

對於解密,一般來說加密的數據長度本身就是8的倍數,所以只需要NoPadding就可以了,若加密的數據長度不是8,就需要用PKCS5Padding,否則解密出來後的明文尾巴的會比原明文的尾巴多出好幾位填充數據。(實測其它模式是,會拋 Given final block not properly padded的異常,這個要結合實際切換一下NoPadding 和 PKCS5Padding)

最上面已經把CBC模式的代碼貼出來了,我就不貼ECB,OFB,CFB模式的了,因爲只需要改動兩行代碼就OK

ECB模式:

			Cipher cipher=Cipher.getInstance("DES/ECB/PKCS5Padding");
			cipher.init(Cipher.ENCRYPT_MODE, key);
CBC模式:

			Cipher cipher=Cipher.getInstance("DES/CBC/PKCS5Padding");
			cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(keyBytes));//直接用keyBytes初始化IV
OFB模式:

			Cipher cipher=Cipher.getInstance("DES/OFB/PKCS5Padding");
			cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(keyBytes));//直接用keyBytes初始化IV
CFB模式:

			Cipher cipher=Cipher.getInstance("DES/CFB/PKCS5Padding");
			cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(keyBytes));//直接用keyBytes初始化IV
寫法基本是一樣的,只是改一下參數即可。

最後調用doFinal方法即可~




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章