首頁 > 軟體

總結一些Java常用的加密演演算法

2021-06-11 19:00:55

一、加密演演算法分類

加密演演算法通常分為三類:

對稱加密

指加密和解密使用相同金鑰的加密演演算法。對稱加密演演算法的優點在於加解密效率高且易於實現。

不可逆加密

不可逆加密演演算法的特徵是加密過程不需要金鑰,並且經過加密的資料無法被解密,只有同樣輸入的輸入資料經過同樣的不可逆演演算法才能得到同樣的加密資料。

非對稱加密

指加密和解密使用不同金鑰的加密演演算法,也稱為公私鑰加密。

二、加密演演算法的應用

1.數位簽章:進行身份認證和資料完整性驗證,主要用到了非對稱金鑰加密技術與數位摘要技術。

2.數位憑證:主要用來確保數位簽章才是安全有效的,數位憑證由獨立的證書發行機構釋出。數位憑證各不相同,每種證書可提供不同級別的可信度,該證書內包含使用者的個人資訊和他的公鑰資訊,同時還附有認證中心的簽名資訊。

3.MD5:對使用者密碼進行加密並進行儲存。

4.網路資料加密:保障傳輸的資料安全,即使被截獲報文,在沒有密匙的情況下也無法得知報文真實內容。

5.SSL協定:在握手階段使用的是非對稱加密,在傳輸階段使用的是對稱加密,也就是說在SSL上傳送的資料是使用對稱金鑰加密的。同時HTTPS也是由SSL+HTTP協定構建的可進行加密傳輸、身份認證(確認使用者端連線的目標主機是否是真實正確的主機)的網路協定。

三、對稱加密演演算法實現

  • 優點:演演算法對訊息雙方公開、計算量小、加密速度快、加密效率高。
  • 缺點:在資料傳送前,傳送方和接收方必須商定好祕鑰,然後雙方儲存好祕鑰。如果一方的祕鑰被洩露,那麼加密資訊就會被破解。

3.1 DES介紹

DES全稱為Data Encryption Standard,即資料加密標準,是一種使用金鑰加密的塊演演算法,1977年被美國聯邦政府的國家標準局確定為聯邦資料處理標準(FIPS),並授權在非密級政府通訊中使用,隨後該演演算法在國際上廣泛流傳開來。不過現在已經有點過時了。

Java程式碼實現:

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);
	}
}

3.2 IDEA介紹

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

 Java程式碼實現

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();
	    }
	}
}

四、不可逆加密演演算法

  • 優點:不可逆、易計算、特徵化
  • 缺點:可能存在雜湊衝突

4.1 MD5介紹

MD5的作用是讓大容量資訊在用數位簽章軟體簽署私人金鑰前被"壓縮"成一種保密的格式
(也就是把一個任意長度的位元組串變換成一定長的十六進位制數位串)。

主要有以下特點:

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

Java程式碼實現

import java.security.MessageDigest;

//利用JDK提供java.security.MessageDigest類實現MD5演演算法
public class MD5Demo {

    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();
    }
}

4.2 SHA1介紹

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

SHA1有如下特性:

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

 Java程式碼實現

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";
		
	}
}

4.3 HMAC 介紹

HMAC 是金鑰相關的 雜湊運算訊息鑑別碼(Hash-based Message Authentication Code),HMAC 運算利用 雜湊演演算法 (MD5、SHA1 等),以 一個金鑰 和 一個訊息 為輸入,生成一個 訊息摘要 作為 輸出。

HMAC 傳送方 和 接收方 都有的 key 進行計算,而沒有這把 key 的第三方,則是 無法計算 出正確的 雜湊值的,這樣就可以 防止資料被篡改。

Java程式碼實現

import net.pocrd.annotation.NotThreadSafe;
import net.pocrd.define.ConstField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Arrays;


@NotThreadSafe
public class HMacHelper {
    private static final Logger logger = LoggerFactory.getLogger(HMacHelper.class);
    private Mac mac;

    /**
     * MAC演演算法可選以下多種演演算法
     * HmacMD5/HmacSHA1/HmacSHA256/HmacSHA384/HmacSHA512
     */
    private static final String KEY_MAC = "HmacMD5";
    public HMacHelper(String key) {
        try {
            SecretKey secretKey = new SecretKeySpec(key.getBytes(ConstField.UTF8), KEY_MAC);
            mac = Mac.getInstance(secretKey.getAlgorithm());
            mac.init(secretKey);
        } catch (Exception e) {
            logger.error("create hmac helper failed.", e);
        }
    }
    public byte[] sign(byte[] content) {
        return mac.doFinal(content);
    }

    public boolean verify(byte[] signature, byte[] content) {
        try {
            byte[] result = mac.doFinal(content);
            return Arrays.equals(signature, result);
        } catch (Exception e) {
            logger.error("verify sig failed.", e);
        }
        return false;
    }
}

五、非對稱加密

  • 優點:非對稱加密與對稱加密相比其安全性更好,只要私鑰不洩露,很難被破解。
  • 缺點:加密和解密花費時間長、速度慢,只適合對少量資料進行加密。

5.1 RSA介紹

RSA是目前最有影響力和最常用的公鑰加密演演算法。它能夠抵抗到目前為止已知的絕大多數密碼攻擊,已被ISO推薦為公鑰資料加密標準。RSA公開金鑰密碼體制的原理是:根據數論,尋求兩個大素數比較簡單,而將它們的乘積進行因式分解卻極其困難,因此可以將乘積公開作為加密金鑰

Java程式碼實現

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;
	}

}

5.2 ECC 介紹

ECC 也是一種 非對稱加密演演算法,主要優勢是在某些情況下,它比其他的方法使用 更小的金鑰,比如 RSA 加密演演算法,提供 相當的或更高等級 的安全級別。不過一個缺點是 加密和解密操作 的實現比其他機制 時間長 (相比 RSA 演演算法,該演演算法對 CPU 消耗嚴重)。

Java程式碼實現

import net.pocrd.annotation.NotThreadSafe;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.KeyFactory;
import java.security.Security;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

@NotThreadSafe
public class EccHelper {
    private static final Logger logger = LoggerFactory.getLogger(EccHelper.class);
    private static final int SIZE = 4096;
    private BCECPublicKey  publicKey;
    private BCECPrivateKey privateKey;

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public EccHelper(String publicKey, String privateKey) {
        this(Base64Util.decode(publicKey), Base64Util.decode(privateKey));
    }

    public EccHelper(byte[] publicKey, byte[] privateKey) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
            if (publicKey != null && publicKey.length > 0) {
                this.publicKey = (BCECPublicKey)keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));
            }
            if (privateKey != null && privateKey.length > 0) {
                this.privateKey = (BCECPrivateKey)keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey));
            }
        } catch (ClassCastException e) {
            throw new RuntimeException("", e);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public EccHelper(String publicKey) {
        this(Base64Util.decode(publicKey));
    }

    public EccHelper(byte[] publicKey) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
            if (publicKey != null && publicKey.length > 0) {
                this.publicKey = (BCECPublicKey)keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public byte[] encrypt(byte[] content) {
        if (publicKey == null) {
            throw new RuntimeException("public key is null.");
        }
        try {
            Cipher cipher = Cipher.getInstance("ECIES", "BC");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            int size = SIZE;
            ByteArrayOutputStream baos = new ByteArrayOutputStream((content.length + size - 1) / size * (size + 45));
            int left = 0;
            for (int i = 0; i < content.length; ) {
                left = content.length - i;
                if (left > size) {
                    cipher.update(content, i, size);
                    i += size;
                } else {
                    cipher.update(content, i, left);
                    i += left;
                }
                baos.write(cipher.doFinal());
            }
            return baos.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public byte[] decrypt(byte[] secret) {
        if (privateKey == null) {
            throw new RuntimeException("private key is null.");
        }
        try {
            Cipher cipher = Cipher.getInstance("ECIES", "BC");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            int size = SIZE + 45;
            ByteArrayOutputStream baos = new ByteArrayOutputStream((secret.length + size + 44) / (size + 45) * size);
            int left = 0;
            for (int i = 0; i < secret.length; ) {
                left = secret.length - i;
                if (left > size) {
                    cipher.update(secret, i, size);
                    i += size;
                } else {
                    cipher.update(secret, i, left);
                    i += left;
                }
                baos.write(cipher.doFinal());
            }
            return baos.toByteArray();
        } catch (Exception e) {
            logger.error("ecc decrypt failed.", e);
        }
        return null;
    }

    public byte[] sign(byte[] content) {
        if (privateKey == null) {
            throw new RuntimeException("private key is null.");
        }
        try {
            Signature signature = Signature.getInstance("SHA1withECDSA", "BC");
            signature.initSign(privateKey);
            signature.update(content);
            return signature.sign();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public boolean verify(byte[] sign, byte[] content) {
        if (publicKey == null) {
            throw new RuntimeException("public key is null.");
        }
        try {
            Signature signature = Signature.getInstance("SHA1withECDSA", "BC");
            signature.initVerify(publicKey);
            signature.update(content);
            return signature.verify(sign);
        } catch (Exception e) {
            logger.error("ecc verify failed.", e);
        }
        return false;
    }
}

到此這篇關於總結一些Java常用的加密演演算法的文章就介紹到這了,更多相關Java加密演演算法內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com