java加密體系-數字簽名(SHA256withRSA)
阿新 • • 發佈:2018-12-26
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(); } }
結果: