Java安全之對稱加密、非對稱加密、數字簽名

孤劍發表於2013-09-11

轉貼: http://www.cnblogs.com/duanxz/p/3195098.html

Java中加密分為兩種方式一個是對稱加密,另一個是非對稱加密。對稱加密是因為加密和解密的鑰匙相同,而非對稱加密是加密和解密的鑰匙不同。

對稱加密與非對稱加密的區別:

對稱加密稱為金鑰加密,速度快,但加密和解密的鑰匙必須相同,只有通訊雙方才能知道金鑰。

非對稱加密稱為公鑰加密,演算法更加複雜,速度慢,加密和解金鑰匙不相同,任何人都可以知道公鑰,只有一個人持有私鑰可以解密。

對稱加密解密:


	/*
	 * 對稱加密
	 */
	private static void secretEncrypt() throws Exception {
		//使用Cipher的例項
		Cipher cipher =Cipher.getInstance("AES");
		
		//得到加密的鑰匙
		SecretKey key =KeyGenerator.getInstance("AES").generateKey();
		
		//初始化加密操作,傳遞加密的鑰匙
		cipher.init(Cipher.ENCRYPT_MODE,key);
		
		//將加密的鑰匙寫入secretKey.key檔案中
		FileOutputStream fosKey=new FileOutputStream("secretKey.key");
		ObjectOutputStream oosSecretKey =new ObjectOutputStream(fosKey);
		oosSecretKey.writeObject(key);
		oosSecretKey.close();
		fosKey.close();
		 
		 //將加密的內容傳遞進去,返回加密後的二進位制資料
		byte [] results =cipher.doFinal("哈哈哈哈哈".getBytes());
		
		//將加密後的二進位制資料寫入到secretContent.dat檔案中
		FileOutputStream fosData=new FileOutputStream("secretContent.dat");
		fosData.write(results);
		fosData.close();
	}
	
	/*
	 * 對稱解密
	 */
	private static void secretDecrypt() throws Exception{
		Cipher cipher =Cipher.getInstance("AES");
		
		//獲取檔案中的key進行解密
		FileInputStream fisKey=new FileInputStream("secretKey.key");
		ObjectInputStream oisKey =new ObjectInputStream(fisKey);
		Key key =(Key)oisKey.readObject();
		oisKey.close();
		fisKey.close();
		
		//初始化解密操作,傳遞加密的鑰匙
		cipher.init(Cipher.DECRYPT_MODE,key);
		
		//獲取檔案中的二進位制資料
		FileInputStream fisDat=new FileInputStream("secretContent.dat");
		//獲取資料第一種方式
		byte [] src=new byte [fisDat.available()];
		int len =fisDat.read(src);
		int total =0;
		while(total<src.length){
			total +=len;
			len=fisDat.read(src,total,src.length-total);
		}
		//執行解密
		byte [] result=cipher.doFinal(src);
		fisDat.close();
		System.out.println(new String(result));
		
//		讀檔案中的資料第二種方式
//		ByteArrayOutputStream baos =new ByteArrayOutputStream();
//		copyStream(fisDat, baos);
//		byte [] result=cipher.doFinal(baos.toByteArray());
//		fisDat.close();
//		baos.close();
	}
	
//	private static void copyStream(InputStream ips,OutputStream ops) throws Exception{
//		byte [] buf =new byte[1024];
//		int len=ips.read(buf);
//		while(len!=-1){
//			ops.write(buf,0,len);
//			len  =ips.read(buf);
//		}
//	}

基於口令的對稱加密與解密

系統自動生成的Key不容易記憶,我們可以使用我們容易記憶的口令同過java自帶的一個工具將它轉換成Key,在解密的時候我們就可以通過口令進行解密。

	/*
	 * 基於口令的對稱加密
	 */
	private static void secretEncrypt() throws Exception {
		//例項化工具
		Cipher cipher2=Cipher.getInstance("PBEWithMD5AndDES");
		
		//使用該工具將基於密碼的形式生成Key
		SecretKey key2=SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(new PBEKeySpec("123".toCharArray()));
		PBEParameterSpec parameterspec=new PBEParameterSpec(new byte[]{1,2,3,4,5,6,7,8},1000);
		
		//初始化加密操作,同時傳遞加密的演算法
		cipher2.init(Cipher.ENCRYPT_MODE,key2,parameterspec);
		
		 //將要加密的資料傳遞進去,返回加密後的資料
		byte [] results =cipher2.doFinal("哈哈哈哈哈".getBytes());
		
		//將加密後的資料寫入到檔案中
		FileOutputStream fosData=new FileOutputStream("zxx.dat");
		fosData.write(results);
		fosData.close();
	}
	
	/*
	 * 基於口令的對稱解密
	 */
	private static void secretDecrypt() throws Exception{
		Cipher cipher2=Cipher.getInstance("PBEWithMD5AndDES");
		SecretKey key2=SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(new PBEKeySpec("123".toCharArray()));
		PBEParameterSpec parameterspec=new PBEParameterSpec(new byte[]{1,2,3,4,5,6,7,8},1000);
		cipher2.init(Cipher.DECRYPT_MODE,key2,parameterspec);
		FileInputStream fisDat=new FileInputStream("zxx.dat");
		byte [] src=new byte [fisDat.available()];
		int len =fisDat.read(src);
		int total =0;
		while(total<src.length){
			total +=len;
			len=fisDat.read(src,total,src.length-total);
		}
		byte [] result=cipher2.doFinal(src);
		fisDat.close();
		System.out.println(new String(result));
	}

非對稱加密解密:

非對稱加密是公鑰加密,私鑰來解密,這個個人做用的少一點,主要針對於大型的網站大型的企業

	/*
	 * 公鑰加密
	 */
	private static void PublicEnrypt()throws Exception {
		Cipher cipher =Cipher.getInstance("RSA");
		//例項化Key
		KeyPairGenerator keyPairGenerator=KeyPairGenerator.getInstance("RSA");
		//獲取一對鑰匙
		KeyPair keyPair=keyPairGenerator.generateKeyPair();
		//獲得公鑰
		Key publicKey=keyPair.getPublic();
		//獲得私鑰 
		Key privateKey=keyPair.getPrivate();
		//用公鑰加密
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);
		byte [] result=cipher.doFinal("傳智播客".getBytes("UTF-8"));
		//將Key寫入到檔案
		saveKey(privateKey,"zxx_private.key");
		//加密後的資料寫入到檔案
		saveData(result,"public_encryt.dat");
	}
	
	/*
	 * 私鑰解密
	 */
	private static void privateDecrypt() throws Exception {
		Cipher cipher=Cipher.getInstance("RSA");
		//得到Key
		Key privateKey=readKey("zxx_private.key");
		//用私鑰去解密
		cipher.init(Cipher.DECRYPT_MODE, privateKey);
		//讀資料來源
		byte [] src =readData("public_encryt.dat");
		//得到解密後的結果
		byte[] result=cipher.doFinal(src);
		//二進位制資料要變成字串需解碼
		System.out.println(new String(result,"UTF-8"));
	}

	private static void saveData(byte[] result, String fileName) throws Exception {
		// TODO Auto-generated method stub
		FileOutputStream fosData=new FileOutputStream(fileName);
		fosData.write(result);
		fosData.close();
	}
	public static void saveKey(Key key,String fileName)throws Exception{
		FileOutputStream fosKey=new FileOutputStream(fileName);
		ObjectOutputStream oosSecretKey =new ObjectOutputStream(fosKey);
		oosSecretKey.writeObject(key);
		oosSecretKey.close();
		fosKey.close();
	}
	private static Key readKey(String fileName) throws Exception {
		FileInputStream fisKey=new FileInputStream(fileName);
		ObjectInputStream oisKey =new ObjectInputStream(fisKey);
		Key key=(Key)oisKey.readObject();
		oisKey.close();
		fisKey.close();
		return key;
	}
	private static byte[] readData(String filename) throws Exception {
		FileInputStream fisDat=new FileInputStream(filename);
		byte [] src=new byte [fisDat.available()];
		int len =fisDat.read(src);
		int total =0;
		while(total<src.length){
			total +=len;
			len=fisDat.read(src,total,src.length-total);
		}
		fisDat.close();
		return src;
	}

數字簽名:

數字簽名的基礎是公鑰和私鑰的非對稱加密,傳送者使用私鑰加密的訊息摘要(簽名),接收者使用公鑰解密訊息摘要以驗證簽名是否是某個人。

要證明這段資料是你發過來的,並且沒有被別人改過,這就需要用到數字簽名,首先我們對整個文件進行md5加密得到16個位元組,然後把訊息摘要和文件發過去,解密者首先對發過來的文件進行解密,解密後得到一個摘要(md5),對接收的文件進行md5加密,得到的md5結果匹配解密後的摘要,如果匹配成功的話證明沒有修改過,我們使用Signature進行簽名

	/* 
	 * 使用私鑰簽名 
	 */  
	private static void sign()throws Exception {  
	    //例項化Key   
	    KeyPairGenerator keyPairGenerator=KeyPairGenerator.getInstance("RSA");  
	    //獲取一對鑰匙   
	    KeyPair keyPair=keyPairGenerator.generateKeyPair();  
	    //獲得公鑰   
	    PublicKey publicKey=keyPair.getPublic();  
	    //獲得私鑰    
	    PrivateKey privateKey=keyPair.getPrivate();  
	    
	    //數字簽名
	    Signature signature =Signature.getInstance("SHA1withRSA");
	    signature.initSign(privateKey);//用私鑰簽名
	    signature.update("這裡簽名".getBytes());//對怎樣的資料進行簽名
	    byte [] sign=signature.sign();  //獲取簽名的結果
	    
	    //儲存公鑰並寫入檔案中 
	    saveKey(publicKey,"zxx_private.key");  
	    //將簽名後的資料寫入到檔案   
	    saveData(sign,"public_encryt.dat");  
	}
	  
	/* 
	 * 公鑰解密 
	 */  
	private static void verify() throws Exception {  
		Signature signture =Signature.getInstance("SHA1withRSA");
		//獲取到公鑰
		PublicKey publicKey=(PublicKey)readKey("zxx_private.key");
		//初始化校驗
		signture.initVerify(publicKey);
		//初始化簽名物件
		signture.update("這裡簽名".getBytes());
		//讀資料來源   
	    byte [] sign =readData("public_encryt.dat");  
	    //返回匹配結果
		boolean isYouSigned=signture.verify(sign);
		//如果返回資料為true則資料沒有發生修改,否則發生修改
		System.out.println(isYouSigned);
	} 


相關文章