zoukankan      html  css  js  c++  java
  • RSA签名和验签Util


    1、DigitalSign类

    import org.apache.commons.codec.binary.Base64;
    
    import javax.crypto.Cipher;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.InputStream;
    import java.security.KeyStore;
    import java.security.Signature;
    import java.security.cert.CertificateException;
    import java.security.cert.CertificateFactory;
    import java.security.cert.X509Certificate;
    import java.security.interfaces.RSAPrivateCrtKey;
    import java.security.interfaces.RSAPublicKey;
    import java.util.Enumeration;
    import java.util.Map;
    import java.util.Set;
    import java.util.concurrent.ConcurrentHashMap;
    
    /**
     * 证书加解密/签名/验签类
     */
    public class DigitalSign {
    	
    	private static DigitalSign single=null;
    
    	/** 编码 格式*/
    	private static String encoding = "UTF-8";
    	/** 算法 */
    	private String arithmetic = "SHA1withRSA";
    
    	/**私钥缓存**/
    	private ConcurrentHashMap<String, RSAPrivateCrtKey> map = new ConcurrentHashMap<String, RSAPrivateCrtKey>();
    
    	private DigitalSign(String encoding){
    	}
    
    	private DigitalSign(){
    
    	}
    	
    	/**
    	 * 初始化 实例
    	 */
    	public static synchronized void init() {  
    		if (single == null) {    
    			single = new DigitalSign(encoding); 
    		}    
    	}
    
    	/**
    	 * 初始化 实例
    	 */
    	public static synchronized void init(String charset) {
    		if (single == null) {
    			single = new DigitalSign();
    			encoding = charset;
    		}
    	}
    
    	//静态工厂方法   
    	public static DigitalSign getInstance() {
    		if (single == null) {    
    			init(); //为空的时候同步实例
    		}    
    		return single;  
    	}
    
    	//静态工厂方法
    	public static DigitalSign getInstance(String charset) {
    		if (single == null) {
    			init(charset); //为空的时候同步实例
    		}
    		return single;
    	}
    	
    	/**
    	 * 私钥签名  
    	 * @param tobeSigned
    	 * @param priKeyPath classpath 下路径
    	 * @param password
    	 * @return
    	 * @throws CryptException
    	 */
    	public String SignMsgByRelativePath(final String tobeSigned, final String priKeyPath, final String password) throws CryptException {
    		RSAPrivateCrtKey priKey = getPriKeyByRelativePath(priKeyPath, password);
    		return sign(priKey, tobeSigned);
    	}
    	
    	
    	/**
    	 * 私钥签名
    	 * @param tobeSigned
    	 * @param priKeyStream 私钥文件流
    	 * @param password
    	 * @return
    	 * @throws CryptException
    	 */
    	public String SignMsgByInputStream(String tobeSigned,InputStream priKeyStream,String password) throws CryptException{
    		RSAPrivateCrtKey priKey = getPriKeyByInputStream(priKeyStream, password);
    		return sign(priKey, tobeSigned);
    	}
    	
    	/**
    	 * 私钥签名
    	 * @param tobeSigned
    	 * @param priKeyPath 私钥绝对路径
    	 * @param password
    	 * @return
    	 * @throws CryptException
    	 */
    	public String signMsgByAbsolutePath(String tobeSigned,String priKeyPath,String password) throws CryptException{
    		RSAPrivateCrtKey priKey = map.get(priKeyPath);
    		if(priKey == null){
    			priKey = getPriKeyByAbsolutePath(priKeyPath, password);
    		}
    		return sign(priKey, tobeSigned);
    	}
    
    
    	/**
    	 * 私钥签名
    	 * @param tobeSigned
    	 * @param priKeyPath 私钥绝对路径
    	 * @param password
    	 * @return
    	 * @throws CryptException
    	 */
    	public String signMsgByAbsolutePath(Map<String, Object> tobeSigned,String priKeyPath,String password) throws CryptException{
    		RSAPrivateCrtKey priKey = map.get(priKeyPath);
    		if(priKey == null){
    			priKey = getPriKeyByAbsolutePath(priKeyPath, password);
    		}
    		return sign(priKey, tobeSigned);
    	}
    	
    	/**
    	 * 公钥验签 
    	 * @param tobeVerfied
    	 * @param plainText
    	 * @param pubKey 文件输入流
    	 * @return
    	 * @throws CryptException
    	 */
    	public boolean verifyMsgByInputSteam(String tobeVerfied,String plainText,InputStream pubKey) throws CryptException{
    		//获取公钥
    		RSAPublicKey pubkey = getPubKeyByInputSteam(pubKey);
    		return verify(pubkey, tobeVerfied, plainText);
    	}
    	
    	/**
    	 * 通过公钥验签
    	 * @param tobeVerified
    	 * @param plainText
    	 * @param pubkeyPath 公钥绝对路径
    	 * @return
    	 * @throws CryptException
    	 */
    	public boolean verifyMsgByAbsolutePath(String tobeVerified,String plainText,String pubkeyPath) throws CryptException{
    		RSAPublicKey pubkey = getPubKeyByAbsolutePath(pubkeyPath);
    		return verify(pubkey, tobeVerified, plainText);
    	}
    
    
    	/**
    	 * 通过公钥验签
    	 * @param tobeVerified
    	 * @param map
    	 * @param pubkeyPath 公钥绝对路径
    	 * @return
    	 * @throws CryptException
    	 */
    	public boolean verifyMsgByAbsolutePath(String tobeVerified,Map<String, Object> map,String pubkeyPath) throws CryptException{
    		RSAPublicKey pubkey = getPubKeyByAbsolutePath(pubkeyPath);
    		return verify(pubkey, tobeVerified, map);
    	}
    	
    	/**
    	 * 公钥验签
    	 * @param tobeVerfied
    	 * @param plainText
    	 * @param CertFile 文件classpath下路径
    	 * @return
    	 * @throws CryptException
    	 */
    	public boolean verifyMsgByRelativePath(String tobeVerfied, String plainText, String CertFile) throws CryptException {
    		RSAPublicKey pubkey = getPubKeyByRelativePath(CertFile);
    		return verify(pubkey, tobeVerfied, plainText);
    	}
    
    	/**
    	 * 使用公钥对数据加密
    	 * @param TobeEncryptMsg 待加密的明文字符串
    	 * @param certFile 公钥路径[相对地址 classpath下]
    	 * @return 加密后的字符串
    	 * @throws CryptException 错误信息
    	 */
    	public String encryptMsg(String TobeEncryptMsg, String certFile) throws CryptException {
    		//获取公钥
    		RSAPublicKey pubKey = getPubKeyByRelativePath(certFile);
    		Cipher instance;
    		try {
    			instance = Cipher.getInstance(pubKey.getAlgorithm());
    			instance.init(Cipher.ENCRYPT_MODE, pubKey);
    			String encryMsg = Base64.encodeBase64String(instance.doFinal(Base64.encodeBase64(TobeEncryptMsg.getBytes(encoding))));
    			return encryMsg;
    		} catch (Exception e) {
    			throw new CryptException("加密失败",e);
    		}
    	}	
    	
    	/**
    	 * 私钥解密
    	 * @param TobeDecodeMsg 待解密的加密字符串
    	 * @param priFile 私钥路径[相对路径 classpath下]
    	 * @param passWord 私钥密码
    	 * @return 解密后的明文字符串
    	 * @throws CryptException 错误信息
    	 */
    	public String decodeMsg(String TobeDecodeMsg, String priFile,
    			String passWord) throws CryptException{
    		RSAPrivateCrtKey priKey = getPriKeyByRelativePath(priFile, passWord);
    		Cipher instance;
    		try {
    			instance = Cipher.getInstance(priKey.getAlgorithm());
    			instance.init(Cipher.DECRYPT_MODE, priKey);
    			String string = new String(Base64.decodeBase64(instance.doFinal(Base64.decodeBase64(TobeDecodeMsg))), encoding);
    			return string;
    		} catch (Exception e) {
    			throw new CryptException("解密失败",e);
    		}
    	}
    
    	/**
    	 * 获取私钥 文件流
    	 * @param keyfileStream
    	 * @param password
    	 * @return
    	 * @throws CryptException
    	 */
    	private RSAPrivateCrtKey getPriKeyByInputStream(InputStream keyfileStream,String password) throws CryptException{
    		return getPriKey(keyfileStream, password);		
    	}
    	
    	/**
    	 * 通过文件绝对路径加载私钥
    	 * @param priKeyPath 绝对路径
    	 * @param password
    	 * @return
    	 * @throws CryptException
    	 */
    	private RSAPrivateCrtKey getPriKeyByAbsolutePath(String priKeyPath,String password) throws CryptException{
    		FileInputStream file;
    		try {
    			file = new FileInputStream(priKeyPath);
    		} catch (FileNotFoundException e) {
    			throw new CryptException("秘钥路径不正确",e);
    		}
    		RSAPrivateCrtKey priKey = getPriKey(file, password);
    		map.put(priKeyPath, priKey);
    		return priKey;
    	}
    	
    	/**
    	 * 获取私钥 [classpath]
    	 * @param KeyFile
    	 * @param passWord
    	 * @return
    	 */
    	private RSAPrivateCrtKey getPriKeyByRelativePath(String KeyFile,String passWord) throws CryptException{
    		//获取项目 相对路径
    		ClassLoader cl = DigitalSign.class.getClassLoader();
    		InputStream fiKeyFile = cl.getResourceAsStream(KeyFile);
    		return getPriKey(fiKeyFile, passWord);
    	}
    	
    	/**
    	 * 获取公钥 [文件输入流]
    	 * @param pubKey
    	 * @return
    	 * @throws CryptException
    	 */
    	private RSAPublicKey getPubKeyByInputSteam(InputStream pubKey) throws CryptException{
    		return getPublicKey(pubKey);
    	}
    
    	
    	/**
    	 * 获取公钥 [classpath下]
    	 * @param CertFile
    	 * @return
    	 */
    	private RSAPublicKey getPubKeyByRelativePath(String CertFile) throws CryptException{
    		//读取公钥文件
    		ClassLoader cl = DigitalSign.class.getClassLoader();
    		InputStream certfile = cl.getResourceAsStream(CertFile);
    		//获取公钥
    		return getPublicKey(certfile);
    	}
    	
    	/**
    	 * 获取公钥 通过绝对路径
    	 * @param pubKeyPath
    	 * @return
    	 * @throws CryptException
    	 */
    	private RSAPublicKey getPubKeyByAbsolutePath(String pubKeyPath) throws CryptException{
    		try{
    			FileInputStream pubKey = new FileInputStream(pubKeyPath);
    			return getPublicKey(pubKey);
    		}catch(Exception e){
    			throw new CryptException("文件读取失败",e);
    		}
    	}
    	
    	/**
    	 * 获取公钥
    	 * @param pubKey 公钥流
    	 * @return
    	 * @throws CryptException
    	 */
    	private RSAPublicKey getPublicKey(InputStream pubKey) throws CryptException{
    		X509Certificate x509cert = null;
    		try {
    			//实例化 x509
    			CertificateFactory cf = CertificateFactory.getInstance("X.509");
    			x509cert = (X509Certificate) cf.generateCertificate(pubKey);
    		} catch (CertificateException e) {
    			if (pubKey != null){
    				try {
    					pubKey.close();
    				} catch (IOException e1) {
    					throw new CryptException("文件流关闭异常",e1);
    				}
    			}			
    			throw new CryptException("初始化公钥异常",e);
    		}
    		//读取公钥
    		RSAPublicKey pubkey = (RSAPublicKey) x509cert.getPublicKey();		
    		return pubkey;
    	}
    	
    	/**
    	 * 获取私钥
    	 * @param priKey
    	 * @param keyPassword
    	 * @return
    	 * @throws CryptException
    	 */
    	private RSAPrivateCrtKey getPriKey(InputStream priKey,String keyPassword) throws CryptException{
    		String keyAlias = null;
    		RSAPrivateCrtKey prikey = null;		
    		try {
    			KeyStore ks = KeyStore.getInstance("PKCS12");
    			ks.load(priKey, keyPassword.toCharArray());
    			
    			Enumeration<?> myEnum = ks.aliases();
    			while (myEnum.hasMoreElements()) {
    				keyAlias = (String) myEnum.nextElement();
    				if (ks.isKeyEntry(keyAlias)) {
    					prikey = (RSAPrivateCrtKey) ks.getKey(keyAlias, keyPassword.toCharArray());
    					break;
    				}
    			}			
    		} catch (Exception e) {
    			if (priKey != null){
    				try {
    					priKey.close();
    				} catch (IOException e1) {
    					throw new CryptException("流关闭异常",e1);
    				}
    			}
    			throw new CryptException("加载私钥失败",e);
    		}
    		
    		if(prikey == null){
    			throw new CryptException("私钥不存在");
    		}
    		
    		return prikey;		
    	}
    	
    	/**
    	 * 签名
    	 * @param priKey 私钥
    	 * @param tobeSigned 待签字符串
     	 * @return 签名结果
    	 * @throws CryptException
    	 */
    	private String sign(RSAPrivateCrtKey priKey,String tobeSigned) throws CryptException{
    		try {
    			Signature sign = Signature.getInstance(arithmetic);
    			sign.initSign(priKey);	
    			sign.update(tobeSigned.getBytes(encoding));	
    			byte signed[] = sign.sign();
    //			byte sign_asc[] = new byte[signed.length * 2];	
    //			Hex2Ascii(signed.length, signed, sign_asc);
    			
    //			return new String(signed,encoding);	
    			return Base64.encodeBase64String(signed).replaceAll("\+", "%2B");
    		} catch (Exception e) {
    			throw new CryptException("签名失败",e);
    		}		
    	}
    
    	/**
    	 * 签名
    	 * @param priKey 私钥
    	 * @param map 待签字符串
    	 * @return 签名结果
    	 * @throws CryptException
    	 */
    	private String sign(RSAPrivateCrtKey priKey,Map<String, Object> map) throws CryptException{
    		try {
    			String tobeSigned = appendMap(map);
    			Signature sign = Signature.getInstance(arithmetic);
    			sign.initSign(priKey);
    			sign.update(tobeSigned.getBytes(encoding));
    			byte signed[] = sign.sign();
    //			byte sign_asc[] = new byte[signed.length * 2];
    //			Hex2Ascii(signed.length, signed, sign_asc);
    
    //			return new String(signed,encoding);
    			return Base64.encodeBase64String(signed).replaceAll("\+", "%2B");
    		} catch (Exception e) {
    			throw new CryptException("签名失败",e);
    		}
    	}
    
    
    	/**
    	 * 连接参数
    	 * @param map
    	 * @return
    	 */
    	private static String appendMap(Map<String, Object> map){
    		Set<String> keySet = map.keySet();
    		StringBuilder sb = new StringBuilder();
    		for (String mapKey : keySet){
    			String value = (String)map.get(mapKey);
    			sb.append(mapKey).append("=").append(value).append("&");
    		}
    		return  sb.toString();
    	}
    	
    	/**
    	 * 验证签名
    	 * @param pubkey 公钥
    	 * @param tobeVerfied 已签名字符串
    	 * @param plainText 待校验字符串
    	 * @return true || false
    	 * @throws CryptException
    	 */
    	private boolean verify(RSAPublicKey pubkey,String tobeVerfied,String plainText) throws CryptException{
    		try {
    			Signature verify = Signature.getInstance(arithmetic);
    			verify.initVerify(pubkey);
    //			byte signeddata[] = new byte[tobeVerfied.length() / 2];
    //			Ascii2Hex(tobeVerfied.length(), tobeVerfied.getBytes(encoding), signeddata);	
    			verify.update(plainText.getBytes(encoding));	
    			
    			return verify.verify(Base64.decodeBase64(tobeVerfied.replaceAll("%2B", "\+")));
    		} catch (Exception e) {
    			throw new CryptException("验签失败",e);
    		}		
    	}
    
    
    	/**
    	 * 验证签名
    	 * @param pubkey 公钥
    	 * @param tobeVerfied 已经签名的map
    	 * @param map 待校验的map
    	 * @return true || false
    	 * @throws CryptException
    	 */
    	private boolean verify(RSAPublicKey pubkey,String tobeVerfied,Map<String, Object> map) throws CryptException{
    		try {
    			String plainText =  appendMap(map);
    			Signature verify = Signature.getInstance(arithmetic);
    			verify.initVerify(pubkey);
    //			byte signeddata[] = new byte[tobeVerfied.length() / 2];
    //			Ascii2Hex(tobeVerfied.length(), tobeVerfied.getBytes(encoding), signeddata);
    			verify.update(plainText.getBytes(encoding));
    
    			return verify.verify(Base64.decodeBase64(tobeVerfied.replaceAll("%2B", "\+")));
    		} catch (Exception e) {
    			throw new CryptException("验签失败",e);
    		}
    	}
    }
    
    
    
    

    2、CryptException异常类

    
    /**
     * 密钥异常类
     */
    public class CryptException extends Exception{
    
    	private static final long serialVersionUID = 2843021655596315128L;
    
    	public CryptException(String message){
    		super(message);
    	}
    
    	public CryptException(String message, Throwable cause) {
    		super(message, cause);
    	}
    
    	public CryptException(Throwable cause) {
    		super(cause);
    	}
    }
    
    
    

    3、加签示例

    Map<String, String> map = new TreeMap<String, String>();
    //....省略map put值...
    String sign = DigitalSign.getInstance().signMsgByAbsolutePath(map, path, 
    password);
    map.put("sign", sign);
    

    4、验签示例

    map.remove("sign");
    DigitalSign digitalSign = DigitalSign.getInstance();
    boolean result = digitalSign.verifyMsgByAbsolutePath(sign, params, merchCertPath);
    
  • 相关阅读:
    在VirtualBox安装debian8.8(完整版)
    Ubuntu18.04 离线安装 docker
    基于JWT的Token认证机制及安全问题
    BTree
    ConcurrentHashMap原理
    Utf8BomRemover
    Spring源码下载
    【intellij idea】Project Structure 讲解 Ctrl+Alt+Shift+S
    idea使用过程中, maven包已经正常下载,但是项目中依然无法引入,提示不存在
    java正则判断字符串是否含有中文、数字、字母
  • 原文地址:https://www.cnblogs.com/ranandrun/p/DigitalSign.html
Copyright © 2011-2022 走看看