总结一些Java常用的加密算法


Posted in Java/Android onJune 11, 2021

一、加密算法分类

加密算法通常分为三类:

对称加密

指加密和解密使用相同密钥的加密算法。对称加密算法的优点在于加解密效率高且易于实现。

不可逆加密

不可逆加密算法的特征是加密过程不需要密钥,并且经过加密的数据无法被解密,只有同样输入的输入数据经过同样的不可逆算法才能得到同样的加密数据。

非对称加密

指加密和解密使用不同密钥的加密算法,也称为公私钥加密。

二、加密算法的应用

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加密算法内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Java/Android 相关文章推荐
idea搭建可运行Servlet的Web项目
Jun 26 Java/Android
Spring Boot 启动、停止、重启、状态脚本
Jun 26 Java/Android
java设计模式--七大原则详解
Jul 21 Java/Android
Spring Security中用JWT退出登录时遇到的坑
Oct 16 Java/Android
Java异常处理try catch的基本用法
Dec 06 Java/Android
关于maven依赖 ${xxx.version}报错问题
Jan 18 Java/Android
Java实现学生管理系统(IO版)
Feb 24 Java/Android
Spring Bean是如何初始化的详解
Mar 22 Java/Android
Flutter集成高德地图并添加自定义Maker的实践
Apr 07 Java/Android
springcloud整合seata
May 20 Java/Android
JavaScript正则表达式实现注册信息校验功能
May 30 Java/Android
Android移动应用开发指南之六种布局详解
Sep 23 Java/Android
springboot @ConfigurationProperties和@PropertySource的区别
教你用Java Swing实现自助取款机系统
手把手教你用SpringBoot将文件打包成zip存放或导出
为什么在foreach循环中JAVA集合不能添加或删除元素
Jun 11 #Java/Android
源码解读Spring-Integration执行过程
浅谈Java实现分布式事务的三种方案
分享一些Java的常用工具
You might like
php 图片上传类代码
2009/07/17 PHP
apache mysql php 源码编译使用方法
2012/05/03 PHP
PHP类与对象中的private访问控制的疑问
2012/11/01 PHP
php恢复数组的key为数字序列的方法
2015/04/28 PHP
增强用户体验友好性之jquery easyui window 窗口关闭时的提示
2012/06/22 Javascript
返回页面顶部top按钮通过锚点实现(自写)
2013/08/30 Javascript
javascript计时器事件使用详解
2014/01/07 Javascript
IE6中链接A的href为javascript协议时不在当前页面跳转
2014/06/05 Javascript
基于JavaScript实现高德地图和百度地图提取行政区边界经纬度坐标
2016/01/22 Javascript
ECMAScript6 新特性范例大全
2017/03/24 Javascript
利用Vue.js+Node.js+MongoDB实现一个博客系统(附源码)
2017/04/24 Javascript
javascript回调函数的概念理解与用法分析
2017/05/27 Javascript
详解vue-router 命名路由和命名视图
2018/06/01 Javascript
详解Vue Elementui中的Tag与页面其它元素相互交互的两三事
2018/09/25 Javascript
javascript跳转与返回和刷新页面的实例代码
2019/11/20 Javascript
Vue v-for中的 input 或 select的值发生改变时触发事件操作
2020/08/31 Javascript
小程序实现列表倒计时功能
2021/01/29 Javascript
[01:17:55]VGJ.T vs Mineski 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/20 DOTA
[54:43]DOTA2-DPC中国联赛 正赛 CDEC vs Dynasty BO3 第一场 2月22日
2021/03/11 DOTA
Python实现随机生成有效手机号码及身份证功能示例
2017/06/05 Python
python pygame实现方向键控制小球
2019/05/17 Python
pycharm如何实现跨目录调用文件
2020/02/28 Python
对CSS3选择器的研究(详解)
2016/09/16 HTML / CSS
让IE6支持css3,让 IE7、IE8 都支持CSS3
2011/10/09 HTML / CSS
物理系毕业生自荐书范文
2014/02/22 职场文书
就业意向书范文
2014/04/01 职场文书
公司贷款承诺书
2014/05/30 职场文书
运动会400米加油稿(8篇)
2014/09/22 职场文书
微笑面对生活演讲稿
2014/09/23 职场文书
企业领导班子四风对照检查材料
2014/09/27 职场文书
公司行政主管岗位职责
2015/04/09 职场文书
公司开业致辞
2015/07/29 职场文书
2016年公司中秋节致辞
2015/11/26 职场文书
某药房的新员工入职告知书!
2019/07/15 职场文书
SpringAop日志找不到方法的处理
2021/06/21 Java/Android
详解JS数组方法
2021/11/20 Javascript