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

SnailClimb發表於2018-03-09

本文主要對訊息摘要演算法和加密演算法做了整理,包括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

複製程式碼

如果想要獲取更多我的原創文章,歡迎關注我的微信公眾號:"Java面試通關手冊" 。無套路,希望能與您共同進步,互相學習。

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

相關文章