常見安全算法(MD5、SHA1、Base64等等)

本文主要對消息摘要算法和加密算法做了整理,包括MD5、SHA、DES、AES、RSA等,並且提供了相應算法的Java實現和測試。

一 消息摘要算法

1. 簡介:

  • 消息摘要算法的主要特徵是加密過程不需要密鑰,並且經過加密的數據無法被解密
  • 只有輸入相同的明文數據經過相同的消息摘要算法才能得到相同的密文。
  • 消息摘要算法主要應用在“數字簽名”領域,作爲對明文的摘要算法。
  • 著名的摘要算法有RSA公司的MD5算法和SHA-1算法及其大量的變體

2. 特點:

  1. 無論輸入的消息有多長,計算出來的消息摘要的長度總是固定的。
  2. 消息摘要看起來是“僞隨機的”。也就是說對相同的信息求摘要結果相同。
  3. 消息輕微改變生成的摘要變化會很大
  4. 只能進行正向的信息摘要,而無法從摘要中恢復出任何的消息,甚至根本就找不到任何與原信息相關的信息

3. 應用:

消息摘要算法最常用的場景就是數字簽名以及數據(密碼)加密了。(一般平時做項目用的比較多的就是使用MD5對用戶密碼進行加密)

4. 何謂數字簽名:

數字簽名主要用到了非對稱密鑰加密技術與數字摘要技術。數字簽名技術是將摘要信息用發送者的私鑰加密,與原文一起傳送給接收者。接收者只有用發送者的公鑰才能解密被加密的摘要信息,然後用HASH函數對收到的原文產生一個摘要信息,與解密的摘要信息對比。 如果相同,則說明收到的信息是完整的,在傳輸過程中沒有被修改,否則說明信息被修改過.

因此數字簽名能夠驗證信息的完整性。 數字簽名是個加密的過程,數字簽名驗證是個解密的過程。

5. 常見消息/數字摘要算法:

MD5:

簡介:

MD5的作用是讓大容量信息在用數字簽名軟件簽署私人密鑰前被”壓縮”成一種保密的格式 (也就是把一個任意長度的字節串變換成一定長的十六進制數字串)。

特點:

  1. 壓縮性: 任意長度的數據,算出的MD5值長度都是固定的。
  2. 容易計算: 從原數據計算出MD5值很容易。
  3. 抗修改性: 對原數據進行任何改動,哪怕只修改1個字節,所得到的MD5值都有很大區別。
  4. 強抗碰撞: 已知原數據和其MD5值,想找到一個具有相同MD5值的數據(即僞造數據)是非常困難的。

代碼實現:

利用JDK提供java.security.MessageDigest類實現MD5算法:

package com.snailclimb.ks.securityAlgorithm;

import java.security.MessageDigest;

public class MD5Demo {

    // test
    public static void main(String[] args) {
        System.out.println(getMD5Code("你若安好,便是晴天"));
    }

    private MD5Demo() {
    }

    // md5加密
    public static String getMD5Code(String message) {
        String md5Str = "";
        try {
        	//創建MD5算法消息摘要
            MessageDigest md = MessageDigest.getInstance("MD5");
            //生成的哈希值的字節數組
            byte[] md5Bytes = md.digest(message.getBytes());
            md5Str = bytes2Hex(md5Bytes);
        }catch(Exception e) {
            e.printStackTrace();
        }
        return md5Str;
    }

    // 2進制轉16進制
    public static String bytes2Hex(byte[] bytes) {
        StringBuffer result = new StringBuffer();
        int temp;
        try {
            for (int i = 0; i < bytes.length; i++) {
                temp = bytes[i];
                if(temp < 0) {
                    temp += 256;
                }
                if (temp < 16) {
                    result.append("0");
                }
                result.append(Integer.toHexString(temp));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result.toString();
    }
}

結果:

6bab82679914f7cb480a120b532ffa80

注意MessageDigest類的幾個方法:

static MessageDigest getInstance(String algorithm)//返回實現指定摘要算法的MessageDigest對象
byte[] digest(byte[] input)//使用指定的字節數組對摘要執行最終更新,然後完成摘要計算。 

不利用Java提供的java.security.MessageDigest類實現MD5算法:

package com.snailclimb.ks.securityAlgorithm;

public class MD5{
    /*
    *四個鏈接變量
    */
    private final int A=0x67452301;
    private final int B=0xefcdab89;
    private final int C=0x98badcfe;
    private final int D=0x10325476;
    /*
    *ABCD的臨時變量
    */
    private int Atemp,Btemp,Ctemp,Dtemp;
     
    /*
    *常量ti
    *公式:floor(abs(sin(i+1))×(2pow32)
    */
    private final int K[]={
        0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,
        0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,0x698098d8,
        0x8b44f7af,0xffff5bb1,0x895cd7be,0x6b901122,0xfd987193,
        0xa679438e,0x49b40821,0xf61e2562,0xc040b340,0x265e5a51,
        0xe9b6c7aa,0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8,
        0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,0xa9e3e905,
        0xfcefa3f8,0x676f02d9,0x8d2a4c8a,0xfffa3942,0x8771f681,
        0x6d9d6122,0xfde5380c,0xa4beea44,0x4bdecfa9,0xf6bb4b60,
        0xbebfbc70,0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05,
        0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,0xf4292244,
        0x432aff97,0xab9423a7,0xfc93a039,0x655b59c3,0x8f0ccc92,
        0xffeff47d,0x85845dd1,0x6fa87e4f,0xfe2ce6e0,0xa3014314,
        0x4e0811a1,0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391};
    /*
    *向左位移數,計算方法未知
    */
    private final int s[]={7,12,17,22,7,12,17,22,7,12,17,22,7,
        12,17,22,5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
        4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,6,10,
        15,21,6,10,15,21,6,10,15,21,6,10,15,21};
     
     
    /*
    *初始化函數
    */
    private void init(){
        Atemp=A;
        Btemp=B;
        Ctemp=C;
        Dtemp=D;
    }
    /*
    *移動一定位數
    */
    private    int    shift(int a,int s){
        return(a<<s)|(a>>>(32-s));//右移的時候,高位一定要補零,而不是補充符號位
    }
    /*
    *主循環
    */
    private void MainLoop(int M[]){
        int F,g;
        int a=Atemp;
        int b=Btemp;
        int c=Ctemp;
        int d=Dtemp;
        for(int i = 0; i < 64; i ++){
            if(i<16){
                F=(b&c)|((~b)&d);
                g=i;
            }else if(i<32){
                F=(d&b)|((~d)&c);
                g=(5*i+1)%16;
            }else if(i<48){
                F=b^c^d;
                g=(3*i+5)%16;
            }else{
                F=c^(b|(~d));
                g=(7*i)%16;
            }
            int tmp=d;
            d=c;
            c=b;
            b=b+shift(a+F+K[i]+M[g],s[i]);
            a=tmp;
        }
        Atemp=a+Atemp;
        Btemp=b+Btemp;
        Ctemp=c+Ctemp;
        Dtemp=d+Dtemp;
     
    }
    /*
    *填充函數
    *處理後應滿足bits≡448(mod512),字節就是bytes≡56(mode64)
    *填充方式爲先加一個0,其它位補零
    *最後加上64位的原來長度
    */
    private int[] add(String str){
        int num=((str.length()+8)/64)+1;//以512位,64個字節爲一組
        int strByte[]=new int[num*16];//64/4=16,所以有16個整數
        for(int i=0;i<num*16;i++){//全部初始化0
            strByte[i]=0;
        }
        int    i;
        for(i=0;i<str.length();i++){
            strByte[i>>2]|=str.charAt(i)<<((i%4)*8);//一個整數存儲四個字節,小端序
        }
        strByte[i>>2]|=0x80<<((i%4)*8);//尾部添加1
        /*
        *添加原長度,長度指位的長度,所以要乘8,然後是小端序,所以放在倒數第二個,這裏長度只用了32位
        */
        strByte[num*16-2]=str.length()*8;
            return strByte;
    }
    /*
    *調用函數
    */
    public String getMD5(String source){
        init();
        int strByte[]=add(source);
        for(int i=0;i<strByte.length/16;i++){
        int num[]=new int[16];
        for(int j=0;j<16;j++){
            num[j]=strByte[i*16+j];
        }
        MainLoop(num);
        }
        return changeHex(Atemp)+changeHex(Btemp)+changeHex(Ctemp)+changeHex(Dtemp);
     
    }
    /*
    *整數變成16進制字符串
    */
    private String changeHex(int a){
        String str="";
        for(int i=0;i<4;i++){
            str+=String.format("%2s", Integer.toHexString(((a>>i*8)%(1<<8))&0xff)).replace(' ', '0');
 
        }
        return str;
    }
    /*
    *單例
    */
    private static MD5 instance;
    public static MD5 getInstance(){
        if(instance==null){
            instance=new MD5();
        }
        return instance;
    }
     
    private MD5(){};
     
    public static void main(String[] args){
        String str=MD5.getInstance().getMD5("你若安好,便是晴天");
        System.out.println(str);
    }
}

SHA1:

對於長度小於2^64位的消息,SHA1會產生一個160位(40個字符)的消息摘要。當接收到消息的時候,這個消息摘要可以用來驗證數據的完整性。在傳輸的過程中,數據很可能會發生變化,那麼這時候就會產生不同的消息摘要。

SHA1有如下特性:

  • 不可以從消息摘要中復原信息;
  • 兩個不同的消息不會產生同樣的消息摘要,(但會有1x10 ^ 48分之一的機率出現相同的消息摘要,一般使用時忽略)。

代碼實現:

*利用JDK提供java.security.MessageDigest類實現SHA1算法:

package com.snailclimb.ks.securityAlgorithm;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class SHA1Demo {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(getSha1("你若安好,便是晴天"));
	
	}

	public static String getSha1(String str) {
		if (null == str || 0 == str.length()) {
			return null;
		}
		char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
		try {
			//創建SHA1算法消息摘要對象
			MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
			//使用指定的字節數組更新摘要。
			mdTemp.update(str.getBytes("UTF-8"));
			//生成的哈希值的字節數組
			byte[] md = mdTemp.digest();
			//SHA1算法生成信息摘要關鍵過程
			int j = md.length;
		    char[] buf = new char[j * 2];
			int k = 0;
			for (int i = 0; i < j; i++) {
				byte byte0 = md[i];
				buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
				buf[k++] = hexDigits[byte0 & 0xf];
			}
			return new String(buf);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return "0";
		
	}
}

結果:

8ce764110a42da9b08504b20e26b19c9e3382414

二 加密算法

1. 簡介:

  • 加密技術包括兩個元素:加密算法和密鑰。
  • 加密算法是將普通的文本(或者可以理解的信息)與一串數字(密鑰)的結合,產生不可理解的密文的步驟。
  • 密鑰是用來對數據進行編碼和解碼的一種算法。
  • 在安全保密中,可通過適當的密鑰加密技術和管理機制來保證網絡的信息通訊安全。

2. 分類:

密鑰加密技術的密碼體制分爲對稱密鑰體制和非對稱密鑰體制兩種。相應地,對數據加密的技術分爲兩類,即對稱加密(私人密鑰加密)和非對稱加密(公開密鑰加密)。

對稱加密以數據加密標準(DES,Data Encryption Standard)算法爲典型代表,非對稱加密通常以RSA(Rivest Shamir Adleman)算法爲代表。

對稱加密的加密密鑰和解密密鑰相同。非對稱加密的加密密鑰和解密密鑰不同,加密密鑰可以公開而解密密鑰需要保密

3. 應用:

常被用在電子商務或者其他需要保證網絡傳輸安全的範圍。

4. 對稱加密:

加密密鑰和解密密鑰相同的加密算法。

對稱加密算法使用起來簡單快捷,密鑰較短,且破譯困難,除了數據加密標準(DES), 另一個對稱密鑰加密系統是國際數據加密算法(IDEA),它比DES的加密性好,而且對計算機功能要求也沒有那麼高。IDEA加密標準由PGP(Pretty Good Privacy)系統使用。

DES:

DES全稱爲Data Encryption Standard,即數據加密標準,是一種使用密鑰加密的塊算法,現在已經過時。

代碼實現:

DES算法實現 :

package com.snailclimb.ks.securityAlgorithm;

import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.SecretKeyFactory;
import javax.crypto.SecretKey;
import javax.crypto.Cipher;

/**
 * DES加密介紹 DES是一種對稱加密算法,所謂對稱加密算法即:加密和解密使用相同密鑰的算法。DES加密算法出自IBM的研究,
 * 後來被美國政府正式採用,之後開始廣泛流傳,但是近些年使用越來越少,因爲DES使用56位密鑰,以現代計算能力,
 * 24小時內即可被破解。雖然如此,在某些簡單應用中,我們還是可以使用DES加密算法,本文簡單講解DES的JAVA實現 。
 * 注意:DES加密和解密過程中,密鑰長度都必須是8的倍數
 */
public class DesDemo {
	public DesDemo() {
	}

	// 測試
	public static void main(String args[]) {
		// 待加密內容
		String str = "cryptology";
		// 密碼,長度要是8的倍數
		String password = "95880288";

		byte[] result;
		try {
			result = DesDemo.encrypt(str.getBytes(), password);
			System.out.println("加密後:" + result);
			byte[] decryResult = DesDemo.decrypt(result, password);
			System.out.println("解密後:" + new String(decryResult));
		} catch (UnsupportedEncodingException e2) {
			// TODO Auto-generated catch block
			e2.printStackTrace();
		} catch (Exception e1) {
			e1.printStackTrace();
		}
	}

	// 直接將如上內容解密

	/**
	 * 加密
	 * 
	 * @param datasource
	 *            byte[]
	 * @param password
	 *            String
	 * @return byte[]
	 */
	public static byte[] encrypt(byte[] datasource, String password) {
		try {
			SecureRandom random = new SecureRandom();
			DESKeySpec desKey = new DESKeySpec(password.getBytes());
			// 創建一個密匙工廠,然後用它把DESKeySpec轉換成
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
			SecretKey securekey = keyFactory.generateSecret(desKey);
			// Cipher對象實際完成加密操作
			Cipher cipher = Cipher.getInstance("DES");
			// 用密匙初始化Cipher對象,ENCRYPT_MODE用於將 Cipher 初始化爲加密模式的常量
			cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
			// 現在,獲取數據並加密
			// 正式執行加密操作
			return cipher.doFinal(datasource); // 按單部分操作加密或解密數據,或者結束一個多部分操作
		} catch (Throwable e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 解密
	 * 
	 * @param src
	 *            byte[]
	 * @param password
	 *            String
	 * @return byte[]
	 * @throws Exception
	 */
	public static byte[] decrypt(byte[] src, String password) throws Exception {
		// DES算法要求有一個可信任的隨機數源
		SecureRandom random = new SecureRandom();
		// 創建一個DESKeySpec對象
		DESKeySpec desKey = new DESKeySpec(password.getBytes());
		// 創建一個密匙工廠
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");// 返回實現指定轉換的
																			// Cipher
																			// 對象
		// 將DESKeySpec對象轉換成SecretKey對象
		SecretKey securekey = keyFactory.generateSecret(desKey);
		// Cipher對象實際完成解密操作
		Cipher cipher = Cipher.getInstance("DES");
		// 用密匙初始化Cipher對象
		cipher.init(Cipher.DECRYPT_MODE, securekey, random);
		// 真正開始解密操作
		return cipher.doFinal(src);
	}
}

結果:

加密後:[B@50cbc42f
解密後:cryptology

IDEA:

  • 這種算法是在DES算法的基礎上發展出來的,類似於三重DES。
  • 發展IDEA也是因爲感到DES具有密鑰太短等缺點。
  • DEA的密鑰爲128位,這麼長的密鑰在今後若干年內應該是安全的。
  • 在實際項目中用到的很少了解即可。

代碼實現:

IDEA算法實現

package com.snailclimb.ks.securityAlgorithm;

import java.security.Key;
import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class IDEADemo {
	public static void main(String args[]) {
		bcIDEA();
	}
	public static void bcIDEA() {
	    String src = "www.xttblog.com security idea";
	    try {
	        Security.addProvider(new BouncyCastleProvider());
	         
	        //生成key
	        KeyGenerator keyGenerator = KeyGenerator.getInstance("IDEA");
	        keyGenerator.init(128);
	        SecretKey secretKey = keyGenerator.generateKey();
	        byte[] keyBytes = secretKey.getEncoded();
	         
	        //轉換密鑰
	        Key key = new SecretKeySpec(keyBytes, "IDEA");
	         
	        //加密
	        Cipher cipher = Cipher.getInstance("IDEA/ECB/ISO10126Padding");
	        cipher.init(Cipher.ENCRYPT_MODE, key);
	        byte[] result = cipher.doFinal(src.getBytes());
	        System.out.println("bc idea encrypt : " + Base64.encodeBase64String(result));
	         
	        //解密
	        cipher.init(Cipher.DECRYPT_MODE, key);
	        result = cipher.doFinal(result);
	        System.out.println("bc idea decrypt : " + new String(result));
	    } catch (Exception e) {
	        e.printStackTrace();
	    }
	}
}

5. 非對稱加密:

  • 與對稱加密算法不同,非對稱加密算法需要兩個密鑰:公開密鑰(publickey)和私有密鑰 (privatekey)。
  • 公開密鑰與私有密鑰是一對,如果用公開密鑰對數據進行加密,只有用對應的私有密鑰才能解密;
  • 如果用私有密鑰對數據進行加密,那麼只有用對應的公開密鑰才能解密。
  • 因爲加密和解密使用的是兩個不同的密鑰,所以這種算法叫作非對稱加密算法。

    RAS:

RSA是目前最有影響力和最常用的公鑰加密算法。它能夠抵抗到目前爲止已知的絕大多數密碼攻擊,已被ISO推薦爲公鑰數據加密標準。

代碼實現:

RAS算法實現:

package com.snailclimb.ks.securityAlgorithm;

import org.apache.commons.codec.binary.Base64;

import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;

/**
 * Created by humf.需要依賴 commons-codec 包
 */
public class RSADemo {

	public static void main(String[] args) throws Exception {
		Map<String, Key> keyMap = initKey();
		String publicKey = getPublicKey(keyMap);
		String privateKey = getPrivateKey(keyMap);

		System.out.println(keyMap);
		System.out.println("-----------------------------------");
		System.out.println(publicKey);
		System.out.println("-----------------------------------");
		System.out.println(privateKey);
		System.out.println("-----------------------------------");
		byte[] encryptByPrivateKey = encryptByPrivateKey("123456".getBytes(), privateKey);
		byte[] encryptByPublicKey = encryptByPublicKey("123456", publicKey);
		System.out.println(encryptByPrivateKey);
		System.out.println("-----------------------------------");
		System.out.println(encryptByPublicKey);
		System.out.println("-----------------------------------");
		String sign = sign(encryptByPrivateKey, privateKey);
		System.out.println(sign);
		System.out.println("-----------------------------------");
		boolean verify = verify(encryptByPrivateKey, publicKey, sign);
		System.out.println(verify);
		System.out.println("-----------------------------------");
		byte[] decryptByPublicKey = decryptByPublicKey(encryptByPrivateKey, publicKey);
		byte[] decryptByPrivateKey = decryptByPrivateKey(encryptByPublicKey, privateKey);
		System.out.println(decryptByPublicKey);
		System.out.println("-----------------------------------");
		System.out.println(decryptByPrivateKey);

	}

	public static final String KEY_ALGORITHM = "RSA";
	public static final String SIGNATURE_ALGORITHM = "MD5withRSA";

	private static final String PUBLIC_KEY = "RSAPublicKey";
	private static final String PRIVATE_KEY = "RSAPrivateKey";

	public static byte[] decryptBASE64(String key) {
		return Base64.decodeBase64(key);
	}

	public static String encryptBASE64(byte[] bytes) {
		return Base64.encodeBase64String(bytes);
	}

	/**
	 * 用私鑰對信息生成數字簽名
	 *
	 * @param data
	 *            加密數據
	 * @param privateKey
	 *            私鑰
	 * @return
	 * @throws Exception
	 */
	public static String sign(byte[] data, String privateKey) throws Exception {
		// 解密由base64編碼的私鑰
		byte[] keyBytes = decryptBASE64(privateKey);
		// 構造PKCS8EncodedKeySpec對象
		PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
		// KEY_ALGORITHM 指定的加密算法
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		// 取私鑰匙對象
		PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
		// 用私鑰對信息生成數字簽名
		Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
		signature.initSign(priKey);
		signature.update(data);
		return encryptBASE64(signature.sign());
	}

	/**
	 * 校驗數字簽名
	 *
	 * @param data
	 *            加密數據
	 * @param publicKey
	 *            公鑰
	 * @param sign
	 *            數字簽名
	 * @return 校驗成功返回true 失敗返回false
	 * @throws Exception
	 */
	public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
		// 解密由base64編碼的公鑰
		byte[] keyBytes = decryptBASE64(publicKey);
		// 構造X509EncodedKeySpec對象
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
		// KEY_ALGORITHM 指定的加密算法
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		// 取公鑰匙對象
		PublicKey pubKey = keyFactory.generatePublic(keySpec);
		Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
		signature.initVerify(pubKey);
		signature.update(data);
		// 驗證簽名是否正常
		return signature.verify(decryptBASE64(sign));
	}

	public static byte[] decryptByPrivateKey(byte[] data, String key) throws Exception {
		// 對密鑰解密
		byte[] keyBytes = decryptBASE64(key);
		// 取得私鑰
		PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
		// 對數據解密
		Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		cipher.init(Cipher.DECRYPT_MODE, privateKey);
		return cipher.doFinal(data);
	}

	/**
	 * 解密<br>
	 * 用私鑰解密
	 *
	 * @param data
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public static byte[] decryptByPrivateKey(String data, String key) throws Exception {
		return decryptByPrivateKey(decryptBASE64(data), key);
	}

	/**
	 * 解密<br>
	 * 用公鑰解密
	 *
	 * @param data
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public static byte[] decryptByPublicKey(byte[] data, String key) throws Exception {
		// 對密鑰解密
		byte[] keyBytes = decryptBASE64(key);
		// 取得公鑰
		X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		Key publicKey = keyFactory.generatePublic(x509KeySpec);
		// 對數據解密
		Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		cipher.init(Cipher.DECRYPT_MODE, publicKey);
		return cipher.doFinal(data);
	}

	/**
	 * 加密<br>
	 * 用公鑰加密
	 *
	 * @param data
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public static byte[] encryptByPublicKey(String data, String key) throws Exception {
		// 對公鑰解密
		byte[] keyBytes = decryptBASE64(key);
		// 取得公鑰
		X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		Key publicKey = keyFactory.generatePublic(x509KeySpec);
		// 對數據加密
		Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);
		return cipher.doFinal(data.getBytes());
	}

	/**
	 * 加密<br>
	 * 用私鑰加密
	 *
	 * @param data
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public static byte[] encryptByPrivateKey(byte[] data, String key) throws Exception {
		// 對密鑰解密
		byte[] keyBytes = decryptBASE64(key);
		// 取得私鑰
		PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
		// 對數據加密
		Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		cipher.init(Cipher.ENCRYPT_MODE, privateKey);
		return cipher.doFinal(data);
	}

	/**
	 * 取得私鑰
	 *
	 * @param keyMap
	 * @return
	 * @throws Exception
	 */
	public static String getPrivateKey(Map<String, Key> keyMap) throws Exception {
		Key key = (Key) keyMap.get(PRIVATE_KEY);
		return encryptBASE64(key.getEncoded());
	}

	/**
	 * 取得公鑰
	 *
	 * @param keyMap
	 * @return
	 * @throws Exception
	 */
	public static String getPublicKey(Map<String, Key> keyMap) throws Exception {
		Key key = keyMap.get(PUBLIC_KEY);
		return encryptBASE64(key.getEncoded());
	}

	/**
	 * 初始化密鑰
	 *
	 * @return
	 * @throws Exception
	 */
	public static Map<String, Key> initKey() throws Exception {
		KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
		keyPairGen.initialize(1024);
		KeyPair keyPair = keyPairGen.generateKeyPair();
		Map<String, Key> keyMap = new HashMap(2);
		keyMap.put(PUBLIC_KEY, keyPair.getPublic());// 公鑰
		keyMap.put(PRIVATE_KEY, keyPair.getPrivate());// 私鑰
		return keyMap;
	}

}

結果:

{RSAPublicKey=Sun RSA public key, 1024 bits
  modulus: 115328826086047873902606456571034976538836553998745367981848911677968062571831626674499650854318207280419960767020601253071739555161388135589487284843845439403614883967713749605268831336418001722701924537624573180276356615050309809260289965219855862692230362893996010057188170525719351126759886050891484226169
  public exponent: 65537, RSAPrivateKey=sun.security.rsa.RSAPrivateCrtKeyImpl@93479}
-----------------------------------
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCkO9PBTOFJQTkzznALN62PU7ixd9YFjXrt2dPOGj3wwhymbOU8HLoCztjwpLXHgbpBUJlGmbURV955M1BkZ1kr5dkZYR5x1gO4xOnu8rEipy4AAMcpFttfiarIZrtzL9pKEvEOxABltVN4yzFDr3IjBqY46aHna7YjwhXI0xHieQIDAQAB
-----------------------------------
MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKQ708FM4UlBOTPOcAs3rY9TuLF31gWNeu3Z084aPfDCHKZs5TwcugLO2PCktceBukFQmUaZtRFX3nkzUGRnWSvl2RlhHnHWA7jE6e7ysSKnLgAAxykW21+Jqshmu3Mv2koS8Q7EAGW1U3jLMUOvciMGpjjpoedrtiPCFcjTEeJ5AgMBAAECgYAK4sxOa8IjEOexv2U92Rrv/SSo3sCY7Z/QVDft2V9xrewoO9+V9HF/7iYDDWffKYInAiimvVl7JM/iSLxza0ZFv29VMpyDcr4TigYmWwBlk7ZbxSTkqLdNwxxldMmEoTn1py53MUm+1V1K3rzNvJjuZaZFAevU7vUnwQwD+JGQYQJBAM9HBaC+dF3PJ2mkXekHpDS1ZPaSFdrdzd/GvHFi/cJAMM+Uz6PmpkosNXRtOpSYWwlOMRamLZtrHhfQoqSk3S8CQQDK1qL1jGvVdqw5OjqxktR7MmOsWUVZdWiBN+6ojxBgA0yVn0n7vkdAAgEZBj89WG0VHPEu3hd4AgXFZHDfXeDXAkBvSn7nE9t/Et7ihfI2UHgGJO8UxNMfNMB5Skebyb7eMYEDs67ZHdpjMOFypcMyTatzj5wjwQ3zyMvblZX+ONbZAkAX4ysRy9WvL+icXLUo0Gfhkk+WrnSyUldaUGH0y9Rb2kecn0OxN/lgGlxSvB+ac910zRHCOTl+Uo6nbmq0g3PFAkAyqA4eT7G9GXfncakgW1Kdkn72w/ODpozgfhTLNX0SGw1ITML3c4THTtH5h3zLi3AF9zJO2O+K6ajRbV0szHHI
-----------------------------------
[B@387c703b
-----------------------------------
[B@224aed64
-----------------------------------
la4Hc4n/UbeBu0z9iLRuwKVv014SiOJMXkO5qdJvKBsw0MlnsrM+89a3p73yMrb1dAnCU/2kgO0PtFpvmG8pzxTe1u/5nX/25iIyUXALlwVRptJyjzFE83g2IX0XEv/Dxqr1RCRcrMHOLQM0oBoxZCaChmyw1Ub4wsSs6Ndxb9M=
-----------------------------------
true
-----------------------------------
[B@c39f790
-----------------------------------
[B@71e7a66b

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