1. 程式人生 > >java加密體系-數字簽名(SHA256withRSA)

java加密體系-數字簽名(SHA256withRSA)

package com.mpush.rsa;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.StringWriter;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMReader;
import org.bouncycastle.openssl.PEMWriter;
import org.bouncycastle.openssl.PasswordFinder;
import org.bouncycastle.util.encoders.Base64;

/**
 * RSA工具
 * @author luke
 * 2018年9月19日
 */
public class LukeRsa {

    /**加密演算法RSA*/
    public static final String KEY_ALGORITHM = "RSA";

    /** 填充方式*/
    public static final String KEY_ALGORITHM_PADDING = "RSA/ECB/PKCS1Padding";
	
    /**金鑰位數 1024 2048*/
    public static final int RAS_KEY_SIZE = 2048;    
    
    /**生成沒有加過密的公私鑰*/
    public static Map<String, Object> createKey(String algorithm,int keysize) throws Exception {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(algorithm);
        keyPairGen.initialize(keysize);
        KeyPair keyPair = keyPairGen.generateKeyPair();
        
        //通過物件 KeyPair 獲取RSA公私鑰物件RSAPublicKey RSAPrivateKey
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        
        //公私鑰物件存入map中
        Map<String, Object> keyMap = new HashMap<String, Object>(2);
        keyMap.put("publicKey", publicKey);
        keyMap.put("privateKey", privateKey);
        return keyMap;
    }
    
    /**生成加過密的公私鑰 pkcs#1格式私鑰 pkcs#8格式公鑰*/
    public static Map<String, Object> createEncryKeyStr(String algorithm,int keysize,String privateKeyPwd) throws Exception {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(algorithm);
        keyPairGen.initialize(keysize);
        KeyPair keyPair = keyPairGen.generateKeyPair();
        
        //通過物件 KeyPair 獲取RSA公私鑰物件RSAPublicKey RSAPrivateKey
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        
        String pubKeyStr = 	new String(Base64.encode(publicKey.getEncoded()));
        String pkcs8Str = new String(Base64.encode(privateKey.getEncoded()));
        System.out.println(pkcs8Str);//從輸出結果可以知道是PKCS#8格式的
       
        System.out.println(LukeDES3.encode3Des(privateKeyPwd, privateKey.getEncoded()));
        
        //私鑰加密
		String privateKeyStr = LukeRsa.privateKeyPwdToPKCS1(privateKey, privateKeyPwd);//使用BC加密私鑰格式會被轉為PKSC#1格式
		
        //公私鑰物件存入map中
        Map<String, Object> keyMap = new HashMap<String, Object>(2);
        keyMap.put("publicKeyStr", pubKeyStr);
        keyMap.put("privateKeyStr", privateKeyStr);
        return keyMap;
    }
    
    /**
     * 將私鑰轉為PKCS#1格式私鑰(加密)
     * @param privateKey
     * @param filePasswd
     * @return
     */
	private static String privateKeyPwdToPKCS1(PrivateKey privateKey,String filePasswd){
		Security.addProvider(new BouncyCastleProvider());
		StringWriter sw = new StringWriter();
		PEMWriter writer = new PEMWriter(sw); 
		try {
			  writer.writeObject(privateKey, "DESEDE", filePasswd.toCharArray(), 
			    new SecureRandom()); 
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			try {
				if(writer !=null){
					writer.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		return sw.toString();
    }
	
	/**
	 * 將私鑰轉為PKCS#1格式私鑰(沒有加密)
	 * @param privateKey
	 * @return
	 */
	private static String privateKeyNoPwdToPKCS1(PrivateKey privateKey){
		Security.addProvider(new BouncyCastleProvider());
		StringWriter sw = new StringWriter();
		PEMWriter writer = new PEMWriter(sw); 
		try {
			  writer.writeObject(privateKey);
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			try {
				if(writer !=null){
					writer.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		return sw.toString();
    }
	
	/**
	 * 將私鑰字串生成檔案
	 * @param privateKeyStr
	 * @param filePath
	 */
	public static void createPrivateKeyFile(String privateKeyStr,String filePath){
		try {
			File file = new File(filePath);
			PrintStream ps = new PrintStream(new FileOutputStream(file));
			ps.print(privateKeyStr);
			ps.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 從pkcs#1私鑰檔案 得到RSA公私鑰物件
	 * @param filePath RSA私鑰檔案路徑 (PEM檔案已加密)
	 * @param filePasswd 私鑰加密祕鑰
	 * @return 返回RSA公私鑰物件
	 */
	public static Map<String,Object> getRSAPrivateKeyEncrypted(String filePath,final String filePasswd) {
		FileInputStream fis = null;
		ByteArrayInputStream bais = null;
		Map<String,Object> map = new HashMap<String, Object>();
		try {
				fis = new FileInputStream(new File(filePath));
				byte[] fileContent = new byte[fis.available()];
				fis.read(fileContent);

				Security.addProvider(new BouncyCastleProvider());
				bais = new ByteArrayInputStream(fileContent);
				PEMReader reader = new PEMReader(new InputStreamReader(bais),
						new PasswordFinder() {
							@Override
							public char[] getPassword() {
								return filePasswd.toCharArray();
							}
						});
				//判斷檔案在加密情況下,使用者是否輸入了密碼
				reader.mark(1);
				//System.out.println(reader.markSupported());
				reader.readLine();
				String isEncrytedStr = reader.readLine();
				if(isEncrytedStr.endsWith("ENCRYPTED") && (filePasswd == null || filePasswd.equals(""))){
					map.put("noPasswd", "私鑰檔案已加密,需私鑰密碼");
					return map;
				}
				if(isEncrytedStr.endsWith("ENCRYPTED")){ //檔案型別
					map.put("type", "ENCRYPTED");
				}else{
					map.put("type", "NOENCRYPTED");
				}
				reader.reset();
				
				KeyPair keyPair = (KeyPair) reader.readObject();
				reader.close();
				
				//解密後獲取公鑰和私鑰
				PublicKey pubk = keyPair.getPublic();//pkcs#8格式公鑰
				PrivateKey prik = keyPair.getPrivate();//pkcs#8格式私鑰  //JCERSAPrivateCrtKey
				//System.out.println(prik.getFormat());

				KeyFactory keyFactory = KeyFactory.getInstance("RSA");
				
				KeySpec keySpec = new X509EncodedKeySpec(pubk.getEncoded());
				KeySpec keySpec2 = new PKCS8EncodedKeySpec(prik.getEncoded());
				RSAPublicKey publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
				RSAPrivateKey privateKey = (RSAPrivateKey) keyFactory.generatePrivate(keySpec2);
				
				System.out.println(new String(Base64.encode(privateKey.getEncoded())));//從輸出結果可以知道是PKCS#8格式的
				
				map.put("publicKey", publicKey);
				map.put("privateKey", privateKey);
				
				return map;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (InvalidKeySpecException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
			return map;
		}catch (Exception e) {
			e.printStackTrace();
			return map;
		}finally {
			try {
				if (bais != null) {
					bais.close();
				}
				if (fis != null) {
					fis.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		return null;

	}
	
    public static void main(String[] args) {
		try {
			//生成加密的公私鑰
			String  filePasswd = "555666";
			Map<String, Object> encryKeyStrMap = LukeRsa.createEncryKeyStr(LukeRsa.KEY_ALGORITHM, LukeRsa.RAS_KEY_SIZE, filePasswd);
			System.out.println(encryKeyStrMap.get("publicKeyStr"));
			System.out.println("---------------");
			System.out.println(encryKeyStrMap.get("privateKeyStr"));
			
			//私鑰生成檔案
			//String filePath = "C:\\Users\\NP0612\\Desktop\\test_priv.pem";
		//	LukeRsa.createPrivateKeyFile(encryKeyStrMap.get("privateKeyStr").toString(), filePath);
			
			//從私鑰檔案獲取公私鑰物件
			//LukeRsa.getRSAPrivateKeyEncrypted(filePath, filePasswd);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
    
}
package com.mpush.rsa;

import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.util.Map;

public class SignTest {

	public static final String SIGNATURE_ALGORITHM = "SHA256withRSA";

	public static final String ENCODE_ALGORITHM = "SHA-256";

	public static final String PLAIN_TEXT = "test string";

	public static void main(String[] args) throws Exception {
		Map<String, Object> keyMap = LukeRsa.createKey(LukeRsa.KEY_ALGORITHM, LukeRsa.RAS_KEY_SIZE);
		PublicKey publicKey = (PublicKey) keyMap.get("publicKey");
		PrivateKey privateKey = (PrivateKey) keyMap.get("privateKey");
		byte[] signBytes = sign(privateKey, PLAIN_TEXT);
		System.out.println(verifySign(publicKey, PLAIN_TEXT, signBytes));
	}

	/**
	 * 簽名
	 * @param privateKey  私鑰
	 * @param plain_text 明文
	 * @return
	 */
	public static byte[] sign(PrivateKey privateKey, String plainText) {
		MessageDigest messageDigest;
		byte[] signed = null;
		try {
			messageDigest = MessageDigest.getInstance(ENCODE_ALGORITHM);
			messageDigest.update(plainText.getBytes());
			byte[] outputDigest_sign = messageDigest.digest();
			System.out.println("SHA-256編碼後-----》"
					+ bytesToHexString(outputDigest_sign));
			Signature Sign = Signature.getInstance(SIGNATURE_ALGORITHM);
			Sign.initSign(privateKey);
			Sign.update(outputDigest_sign);
			signed = Sign.sign();
			System.out.println("SHA256withRSA簽名後-----》"
					+ bytesToHexString(signed));
		} catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
			e.printStackTrace();
		}
		return signed;
	}
	
	/**
	 * 驗籤
	 * @param publicKey 公鑰
	 * @param plain_text 明文
	 * @param signed 簽名
	 */
	public static boolean verifySign(PublicKey publicKey, String plain_text, byte[] signed) {
		MessageDigest messageDigest;
		boolean SignedSuccess=false;
		try {
			messageDigest = MessageDigest.getInstance(ENCODE_ALGORITHM);
			messageDigest.update(plain_text.getBytes());
			byte[] outputDigest_verify = messageDigest.digest();
			//System.out.println("SHA-256加密後-----》" +bytesToHexString(outputDigest_verify));
			Signature verifySign = Signature.getInstance(SIGNATURE_ALGORITHM);
			verifySign.initVerify(publicKey);
			verifySign.update(outputDigest_verify);
			SignedSuccess = verifySign.verify(signed);
			System.out.println("驗證成功?---" + SignedSuccess);
			
		} catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
			e.printStackTrace();
		}
		return SignedSuccess;
	}

	
	/**
	 * bytes[]換成16進位制字串
	 * 
	 * @param src
	 * @return
	 */
	public static String bytesToHexString(byte[] src) {
		StringBuilder stringBuilder = new StringBuilder("");
		if (src == null || src.length <= 0) {
			return null;
		}
		for (int i = 0; i < src.length; i++) {
			int v = src[i] & 0xFF;
			String hv = Integer.toHexString(v);
			if (hv.length() < 2) {
				stringBuilder.append(0);
			}
			stringBuilder.append(hv);
		}
		return stringBuilder.toString();
	}

}

結果: