數字證書就是互聯網通信中標誌通信各方身份信息的一串數字,提供了一種在Internet上驗證通訊實體身份的方式,數字證書不是數字身份證,而是身份認證機構蓋在數字身份證上的一個章或印(或者說加在數字身份證上的一個簽名)。它是由權威機構——CA機構,又稱爲證書受權(Certificate Authority)中心發行的,人們能夠在網上用它來識別對方的身份。java
分爲2大類:密鑰庫(含私鑰,也可能有公鑰)和公鑰證書(僅含公鑰)git
格式 : JKS
擴展名 : .jks/.ks
描述 : 【Java Keystore】密鑰庫的Java實現版本,provider爲SUN
特色 : 密鑰庫和私鑰用不一樣的密碼進行保護
格式 : JCEKS
擴展名 : .jce
描述 : 【JCE Keystore】密鑰庫的JCE實現版本,provider爲SUN JCE
特色 : 相對於JKS安全級別更高,保護Keystore私鑰時採用TripleDES
格式 : PKCS12
擴展名 : .p12/.pfx
描述 : 【PKCS #12】我的信息交換語法標準
特色 : 一、包含私鑰、公鑰及其證書
二、密鑰庫和私鑰用相同密碼進行保護
格式 : BKS
擴展名 : .bks
描述 : Bouncycastle Keystore】密鑰庫的BC實現版本,provider爲BC
特色 : 基於JCE實現
格式 : UBER
擴展名 : .ubr
描述 : 【Bouncycastle UBER Keystore】密鑰庫的BC更安全實現版本,provider爲BC算法
格式 : DER
擴展名 : .cer/.crt/.rsaapache
描述 : 【ASN .1 DER】用於存放證書
特色 : 不含私鑰、二進制數組
格式 : PKCS7
擴展名 : .p7b/.p7r
描述 : 【PKCS #7】加密信息語法標準安全
特色 : 一、p7b以樹狀展現證書鏈,不含私鑰
二、p7r爲CA對證書請求籤名的回覆,只能用於導入app
格式 : CMS
擴展名 : .p7c/.p7m/.p7s
描述 : 【Cryptographic Message Syntax】
特色 : 一、p7c只保存證書
二、p7m:signature with enveloped data
三、p7s:時間戳簽名文件
格式 : PEM
擴展名 : .pem
描述 : 【Printable Encoded Message】
特色 : 一、該編碼格式在RFC1421中定義,其實PEM是【Privacy-Enhanced Mail】的簡寫,但他也一樣普遍運用於密鑰管理
二、ASCII文件
三、通常基於base 64編碼ide
格式 : PKCS10
擴展名 : .p10/.csr
描述 : 【PKCS #10】公鑰加密標準【Certificate Signing Request】
特色 : 一、證書籤名請求文件
二、ASCII文件
三、CA簽名後以p7r文件回覆函數
格式 : SPC
擴展名 : .pvk/.spc
描述 : 【Software Publishing Certificate】
特色 : 微軟公司特有的雙證書文件格式,常常用於代碼簽名,其中
一、pvk用於保存私鑰
二、spc用於保存公鑰 工具
CA中心廣泛採用的規範是X.509[13]系列和PKCS系列,其中主要應用到了如下規範:
X.509是由國際電信聯盟(ITU-T)制定的數字證書標準。在X.500確保用戶名稱唯一性的基礎上,X.509爲X.500用戶名稱提供了通訊實體的鑑別機制,並規定了實體鑑別過程當中普遍適用的證書語法和數據接口。
X.509的最第一版本公佈於1988年。X.509證書由用戶公共密鑰和用戶標識符組成。此外還包括版本號、證書序列號、CA標識符、簽名算法標識、簽發者名稱、證書有效期等信息。這一標準的最新版本是X.509 v3,它定義了包含擴展信息的數字證書。該版數字證書提供了一個擴展信息字段,用來提供更多的靈活性及特殊應用環境下所需的信息傳送。
一個標準的X.509數字證書包含如下一些內容:
PKCS是由美國RSA數據安全公司及其合做夥伴制定的一組公鑰密碼學標準,其中包括證書申請、證書更新、證書做廢表發佈、擴展證書內容以及數字簽名、數字信封的格式等方面的一系列相關協議。到1999年末,PKCS已經公佈瞭如下標準:
PKCS#1:定義RSA公開密鑰算法加密和簽名機制,主要用於組織PKCS#7中所描述的數字簽名和數字信封。
PKCS#3:定義Diffie-Hellman密鑰交換協議。
PKCS#5:描述一種利用從口令派生出來的安全密鑰加密字符串的方法。使用MD2或MD5 從口令中派生密鑰,並採用DES-CBC模式加密。主要用於加密從一個計算機傳送到另外一個計算機的私人密鑰,不能用於加密消息。
PKCS#6:描述了公鑰證書的標準語法,主要描述X.509證書的擴展格式。
PKCS#7:定義一種通用的消息語法,包括數字簽名和加密等用於加強的加密機制,PKCS#7與PEM兼容,因此不需其餘密碼操做,就能夠將加密的消息轉換成PEM消息。
PKCS#8:描述私有密鑰信息格式,該信息包括公開密鑰算法的私有密鑰以及可選的屬性集等。
PKCS#9:定義一些用於PKCS#6證書擴展、PKCS#7數字簽名和PKCS#8私鑰加密信息的屬性類型。
PKCS#10:描述證書請求語法。
PKCS#11:稱爲Cyptoki,定義了一套獨立於技術的程序設計接口,用於智能卡和PCMCIA卡之類的加密設備。
PKCS#12:描述我的信息交換語法標準。描述了將用戶公鑰、私鑰、證書和其餘相關信息打包的語法。
PKCS#13:橢圓曲線密碼體制標準。
PKCS#14:僞隨機數生成標準。
PKCS#15:密碼令牌信息格式標準。
1 package cn.mars.app.txn.xmmsi; 2 3 import java.io.BufferedReader; 4 import java.io.ByteArrayInputStream; 5 import java.io.ByteArrayOutputStream; 6 import java.io.FileInputStream; 7 import java.io.FileNotFoundException; 8 import java.io.IOException; 9 import java.io.InputStream; 10 import java.io.InputStreamReader; 11 import java.math.BigInteger; 12 import java.security.InvalidAlgorithmParameterException; 13 import java.security.InvalidKeyException; 14 import java.security.KeyFactory; 15 import java.security.KeyStore; 16 import java.security.KeyStoreException; 17 import java.security.NoSuchAlgorithmException; 18 import java.security.PrivateKey; 19 import java.security.PublicKey; 20 import java.security.Signature; 21 import java.security.SignatureException; 22 import java.security.UnrecoverableKeyException; 23 import java.security.cert.Certificate; 24 import java.security.cert.CertificateException; 25 import java.security.cert.CertificateFactory; 26 import java.security.cert.X509Certificate; 27 import java.security.spec.InvalidKeySpecException; 28 import java.security.spec.KeySpec; 29 import java.security.spec.PKCS8EncodedKeySpec; 30 import java.security.spec.RSAPrivateKeySpec; 31 import java.security.spec.RSAPublicKeySpec; 32 import java.security.spec.X509EncodedKeySpec; 33 import java.util.Enumeration; 34 35 import javax.crypto.BadPaddingException; 36 import javax.crypto.Cipher; 37 import javax.crypto.IllegalBlockSizeException; 38 import javax.crypto.NoSuchPaddingException; 39 import javax.crypto.SecretKey; 40 import javax.crypto.spec.IvParameterSpec; 41 import javax.crypto.spec.SecretKeySpec; 42 43 import org.apache.commons.codec.binary.Base64; 44 import org.apache.commons.lang.StringUtils; 45 import org.bouncycastle.asn1.ASN1InputStream; 46 import org.bouncycastle.asn1.ASN1Sequence; 47 import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure; 48 import org.bouncycastle.asn1.x509.RSAPublicKeyStructure; 49 /*import org.slf4j.Logger; 50 import org.slf4j.LoggerFactory;*/ 51 import cn.mars.common.component.logger.LOG; 52 import cn.mars.common.component.logger.LogFactory; 53 import cn.mars.app.txn.xmmsi.KeyUtil; 54 55 /** 56 * <strong>Title : CryptoUtil</strong><br> 57 * <strong>Description : 加解密工具類</strong><br> 58 * <strong>Create on : 2015-05-04</strong><br> 59 * 60 * @author linshangqing@cmbc.com.cn<br> 61 */ 62 public abstract class CryptoUtil { 63 /** 64 * 日誌對象 65 */ 66 public static LOG logger = LogFactory.getLogger(CryptoUtil.class); 67 /** 68 * 數字簽名函數入口 69 * 70 * @param plainBytes 71 * 待簽名明文字節數組 72 * @param privateKey 73 * 簽名使用私鑰 74 * @param signAlgorithm 75 * 簽名算法 76 * @return 簽名後的字節數組 77 * @throws Exception 78 */ 79 public static byte[] digitalSign(byte[] plainBytes, PrivateKey privateKey, String signAlgorithm) throws Exception { 80 try { 81 Signature signature = Signature.getInstance(signAlgorithm); 82 signature.initSign(privateKey); 83 signature.update(plainBytes); 84 byte[] signBytes = signature.sign(); 85 86 return signBytes; 87 } catch (NoSuchAlgorithmException e) { 88 throw new Exception(String.format("數字簽名時沒有[%s]此類算法", signAlgorithm)); 89 //throw new Exception(String.format("數字簽名時沒有[%s]此類算法", signAlgorithm)); 90 } catch (InvalidKeyException e) { 91 throw new Exception("數字簽名時私鑰無效"); 92 } catch (SignatureException e) { 93 throw new Exception("數字簽名時出現異常"); 94 } 95 } 96 97 /** 98 * 驗證數字簽名函數入口 99 * 100 * @param plainBytes 101 * 待驗籤明文字節數組 102 * @param signBytes 103 * 待驗籤簽名後字節數組 104 * @param publicKey 105 * 驗籤使用公鑰 106 * @param signAlgorithm 107 * 簽名算法 108 * @return 驗籤是否經過 109 * @throws Exception 110 */ 111 public static boolean verifyDigitalSign(byte[] plainBytes, byte[] signBytes, PublicKey publicKey, String signAlgorithm) throws Exception { 112 boolean isValid = false; 113 try { 114 Signature signature = Signature.getInstance(signAlgorithm); 115 signature.initVerify(publicKey); 116 signature.update(plainBytes); 117 isValid = signature.verify(signBytes); 118 return isValid; 119 } catch (NoSuchAlgorithmException e) { 120 throw new Exception(String.format("驗證數字簽名時沒有[%s]此類算法", signAlgorithm)); 121 } catch (InvalidKeyException e) { 122 throw new Exception("驗證數字簽名時公鑰無效"); 123 } catch (SignatureException e) { 124 throw new Exception("驗證數字簽名時出現異常"); 125 } 126 } 127 128 /** 129 * 驗證數字簽名函數入口 130 * 131 * @param plainBytes 132 * 待驗籤明文字節數組 133 * @param signBytes 134 * 待驗籤簽名後字節數組 135 * @param publicKey 136 * 驗籤使用公鑰 137 * @param signAlgorithm 138 * 簽名算法 139 * @return 驗籤是否經過 140 * @throws Exception 141 */ 142 public static boolean verifyDigitalSign(byte[] plainBytes, byte[] signBytes, X509Certificate cert, String signAlgorithm) throws Exception { 143 boolean isValid = false; 144 try { 145 Signature signature = Signature.getInstance(signAlgorithm); 146 signature.initVerify(cert); 147 signature.update(plainBytes); 148 isValid = signature.verify(signBytes); 149 return isValid; 150 } catch (NoSuchAlgorithmException e) { 151 throw new Exception(String.format("驗證數字簽名時沒有[%s]此類算法", signAlgorithm)); 152 } catch (InvalidKeyException e) { 153 throw new Exception("驗證數字簽名時公鑰無效"); 154 } catch (SignatureException e) { 155 throw new Exception("驗證數字簽名時出現異常"); 156 } 157 } 158 /** 159 * 獲取RSA公鑰對象 160 * 161 * @param filePath 162 * RSA公鑰路徑 163 * @param fileSuffix 164 * RSA公鑰名稱,決定編碼類型 165 * @param keyAlgorithm 166 * 密鑰算法 167 * @return RSA公鑰對象 168 * @throws Exception 169 */ 170 public static PublicKey getRSAPublicKeyByFileSuffix(String filePath, String fileSuffix, String keyAlgorithm) throws Exception { 171 InputStream in = null; 172 String keyType = ""; 173 if ("crt".equalsIgnoreCase(fileSuffix) || "txt".equalsIgnoreCase(fileSuffix) ||"cer".equalsIgnoreCase(fileSuffix)) { 174 keyType = "X.509"; 175 } else if ("pem".equalsIgnoreCase(fileSuffix)) { 176 keyType = "PKCS12"; 177 } else if(("yljf").equalsIgnoreCase(fileSuffix)){ 178 keyType = "yljf"; 179 } else{ 180 keyType = "PKCS12"; 181 } 182 183 try { 184 in = new FileInputStream(filePath); 185 PublicKey pubKey = null; 186 if ("X.509".equals(keyType)) { 187 CertificateFactory factory = CertificateFactory.getInstance(keyType); 188 Certificate cert = factory.generateCertificate(in); 189 pubKey = cert.getPublicKey(); 190 } else if ("PKCS12".equals(keyType)) { 191 BufferedReader br = new BufferedReader(new InputStreamReader(in)); 192 StringBuilder sb = new StringBuilder(); 193 String readLine = null; 194 while ((readLine = br.readLine()) != null) { 195 if (readLine.charAt(0) == '-') { 196 continue; 197 } else { 198 sb.append(readLine); 199 sb.append('\r'); 200 } 201 } 202 X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(Base64.decodeBase64(sb.toString())); 203 KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm); 204 pubKey = keyFactory.generatePublic(pubX509); 205 }else if("yljf".equals(keyType)){ 206 BufferedReader br = new BufferedReader(new InputStreamReader(in, "utf-8")); 207 String s = br.readLine(); 208 ASN1InputStream ain = new ASN1InputStream(hexString2ByteArr(s)); 209 RSAPublicKeyStructure pStruct = RSAPublicKeyStructure.getInstance(ain.readObject()); 210 RSAPublicKeySpec spec = new RSAPublicKeySpec(pStruct.getModulus(), pStruct.getPublicExponent()); 211 KeyFactory kf = KeyFactory.getInstance("RSA"); 212 if (in != null) 213 in.close(); 214 return kf.generatePublic(spec); 215 } 216 217 return pubKey; 218 } catch (FileNotFoundException e) { 219 throw new Exception("公鑰路徑文件不存在"); 220 } catch (CertificateException e) { 221 throw new Exception("生成證書文件錯誤"); 222 } catch (IOException e) { 223 throw new Exception("讀取公鑰異常"); 224 } catch (NoSuchAlgorithmException e) { 225 throw new Exception(String.format("生成密鑰工廠時沒有[%s]此類算法", keyAlgorithm)); 226 } catch (InvalidKeySpecException e) { 227 throw new Exception("生成公鑰對象異常"); 228 } finally { 229 try { 230 if (in != null) { 231 in.close(); 232 } 233 } catch (IOException e) { 234 } 235 } 236 } 237 238 /** 239 * 240 * <br>description : 生成平臺公鑰證書對象 241 * @param b 242 * @return 243 * @version 1.0 244 * @date 2014-7-25上午11:56:05 245 */ 246 private static X509Certificate getCert(String filePath) throws Exception { 247 try { 248 byte[] b = null; 249 InputStream in = null; 250 try{ 251 in = new FileInputStream(filePath); 252 b = new byte[20480]; 253 in.read(b); 254 }finally{ 255 if(null!=in)in.close(); 256 } 257 ByteArrayInputStream bais = new ByteArrayInputStream(b); 258 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 259 X509Certificate x509Certificate = (X509Certificate)cf.generateCertificate(bais); 260 return x509Certificate; 261 } catch (Exception e) { 262 logger.error("",e); 263 throw new Exception("生成公鑰證書對象異常"); 264 } 265 } 266 267 /** 268 * 獲取RSA私鑰對象 269 * 270 * @param filePath 271 * RSA私鑰路徑 272 * @param fileSuffix 273 * RSA私鑰名稱,決定編碼類型 274 * @param password 275 * RSA私鑰保護密鑰 276 * @param keyAlgorithm 277 * 密鑰算法 278 * @return RSA私鑰對象 279 * @throws Exception 280 */ 281 @SuppressWarnings("deprecation") 282 public static PrivateKey getRSAPrivateKeyByFileSuffix(String filePath, String fileSuffix, String password, String keyAlgorithm) 283 throws Exception { 284 String keyType = ""; 285 if ("keystore".equalsIgnoreCase(fileSuffix)) { 286 keyType = "JKS"; 287 } else if ("pfx".equalsIgnoreCase(fileSuffix) || "p12".equalsIgnoreCase(fileSuffix)) { 288 keyType = "PKCS12"; 289 } else if ("jck".equalsIgnoreCase(fileSuffix)) { 290 keyType = "JCEKS"; 291 } else if ("pem".equalsIgnoreCase(fileSuffix) || "pkcs8".equalsIgnoreCase(fileSuffix)) { 292 keyType = "PKCS8"; 293 } else if ("pkcs1".equalsIgnoreCase(fileSuffix)) { 294 keyType = "PKCS1"; 295 } else if ("yljf".equalsIgnoreCase(fileSuffix)) { 296 keyType = "yljf"; 297 } else if ("ldys".equalsIgnoreCase(fileSuffix)) { 298 keyType = "ldys"; 299 } else{ 300 keyType = "JKS"; 301 } 302 303 InputStream in = null; 304 try { 305 in = new FileInputStream(filePath); 306 PrivateKey priKey = null; 307 if ("JKS".equals(keyType) || "PKCS12".equals(keyType) || "JCEKS".equals(keyType)) { 308 KeyStore ks = KeyStore.getInstance(keyType); 309 if (password != null) { 310 char[] cPasswd = password.toCharArray(); 311 ks.load(in, cPasswd); 312 Enumeration<String> aliasenum = ks.aliases(); 313 String keyAlias = null; 314 while (aliasenum.hasMoreElements()) { 315 keyAlias = (String) aliasenum.nextElement(); 316 priKey = (PrivateKey) ks.getKey(keyAlias, cPasswd); 317 if (priKey != null) 318 break; 319 } 320 } 321 }else if("yljf".equals(keyType)){ 322 BufferedReader br = new BufferedReader(new InputStreamReader(in)); 323 String s = br.readLine(); 324 PKCS8EncodedKeySpec priPKCS8=new PKCS8EncodedKeySpec(hexStrToBytes(s)); 325 KeyFactory keyf=KeyFactory.getInstance("RSA"); 326 PrivateKey myprikey=keyf.generatePrivate(priPKCS8); 327 return myprikey; 328 }else if("ldys".equals(keyType)){ 329 byte[] b = new byte[20480]; 330 in.read(b); 331 PKCS8EncodedKeySpec priPKCS8=new PKCS8EncodedKeySpec(b); 332 KeyFactory keyf=KeyFactory.getInstance("RSA"); 333 PrivateKey myprikey=keyf.generatePrivate(priPKCS8); 334 return myprikey; 335 }else { 336 BufferedReader br = new BufferedReader(new InputStreamReader(in)); 337 StringBuilder sb = new StringBuilder(); 338 String readLine = null; 339 while ((readLine = br.readLine()) != null) { 340 if (readLine.charAt(0) == '-') { 341 continue; 342 } else { 343 sb.append(readLine); 344 sb.append('\r'); 345 } 346 } 347 if ("PKCS8".equals(keyType)) { 348 PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decodeBase64(sb.toString())); 349 KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm); 350 priKey = keyFactory.generatePrivate(priPKCS8); 351 } else if ("PKCS1".equals(keyType)) { 352 // RSAPrivateKeyStructure asn1PrivKey = new RSAPrivateKeyStructure((ASN1Sequence) ASN1Sequence.fromByteArray(sb.toString().getBytes())); 353 RSAPrivateKeyStructure asn1PrivKey = new RSAPrivateKeyStructure((ASN1Sequence) ASN1Sequence.fromByteArray(Base64.decodeBase64(sb.toString()))); 354 KeySpec rsaPrivKeySpec = new RSAPrivateKeySpec(asn1PrivKey.getModulus(), asn1PrivKey.getPrivateExponent()); 355 KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm); 356 priKey = keyFactory.generatePrivate(rsaPrivKeySpec); 357 } 358 } 359 360 return priKey; 361 } catch (FileNotFoundException e) { 362 throw new Exception("私鑰路徑文件不存在"); 363 } catch (KeyStoreException e) { 364 throw new Exception("獲取KeyStore對象異常"); 365 } catch (IOException e) { 366 throw new Exception("讀取私鑰異常"); 367 } catch (NoSuchAlgorithmException e) { 368 throw new Exception("生成私鑰對象異常"); 369 } catch (CertificateException e) { 370 throw new Exception("加載私鑰密碼異常"); 371 } catch (UnrecoverableKeyException e) { 372 throw new Exception("生成私鑰對象異常"); 373 } catch (InvalidKeySpecException e) { 374 throw new Exception("生成私鑰對象異常"); 375 } finally { 376 try { 377 if (in != null) { 378 in.close(); 379 } 380 } catch (IOException e) { 381 } 382 } 383 } 384 385 /** 386 * RSA加密 387 * 388 * @param plainBytes 389 * 明文字節數組 390 * @param publicKey 391 * 公鑰 392 * @param keyLength 393 * 密鑰bit長度 394 * @param reserveSize 395 * padding填充字節數,預留11字節 396 * @param cipherAlgorithm 397 * 加解密算法,通常爲RSA/ECB/PKCS1Padding 398 * @return 加密後字節數組,不經base64編碼 399 * @throws Exception 400 */ 401 public static byte[] RSAEncrypt(byte[] plainBytes, PublicKey publicKey, int keyLength, int reserveSize, String cipherAlgorithm) 402 throws Exception { 403 int keyByteSize = keyLength / 8; // 密鑰字節數 404 int encryptBlockSize = keyByteSize - reserveSize; // 加密塊大小=密鑰字節數-padding填充字節數 405 int nBlock = plainBytes.length / encryptBlockSize;// 計算分段加密的block數,向上取整 406 if ((plainBytes.length % encryptBlockSize) != 0) { // 餘數非0,block數再加1 407 nBlock += 1; 408 } 409 410 try { 411 Cipher cipher = Cipher.getInstance(cipherAlgorithm); 412 cipher.init(Cipher.ENCRYPT_MODE, publicKey); 413 414 // 輸出buffer,大小爲nBlock個keyByteSize 415 ByteArrayOutputStream outbuf = new ByteArrayOutputStream(nBlock * keyByteSize); 416 // 分段加密 417 for (int offset = 0; offset < plainBytes.length; offset += encryptBlockSize) { 418 int inputLen = plainBytes.length - offset; 419 if (inputLen > encryptBlockSize) { 420 inputLen = encryptBlockSize; 421 } 422 423 // 獲得分段加密結果 424 byte[] encryptedBlock = cipher.doFinal(plainBytes, offset, inputLen); 425 // 追加結果到輸出buffer中 426 outbuf.write(encryptedBlock); 427 } 428 429 outbuf.flush(); 430 outbuf.close(); 431 return outbuf.toByteArray(); 432 } catch (NoSuchAlgorithmException e) { 433 throw new Exception(String.format("沒有[%s]此類加密算法", cipherAlgorithm)); 434 } catch (NoSuchPaddingException e) { 435 throw new Exception(String.format("沒有[%s]此類填充模式", cipherAlgorithm)); 436 } catch (InvalidKeyException e) { 437 throw new Exception("無效密鑰"); 438 } catch (IllegalBlockSizeException e) { 439 throw new Exception("加密塊大小不合法"); 440 } catch (BadPaddingException e) { 441 throw new Exception("錯誤填充模式"); 442 } catch (IOException e) { 443 throw new Exception("字節輸出流異常"); 444 } 445 } 446 447 /** 448 * RSA解密 449 * 450 * @param encryptedBytes 451 * 加密後字節數組 452 * @param privateKey 453 * 私鑰 454 * @param keyLength 455 * 密鑰bit長度 456 * @param reserveSize 457 * padding填充字節數,預留11字節 458 * @param cipherAlgorithm 459 * 加解密算法,通常爲RSA/ECB/PKCS1Padding 460 * @return 解密後字節數組,不經base64編碼 461 * @throws Exception 462 */ 463 public static byte[] RSADecrypt(byte[] encryptedBytes, PrivateKey privateKey, int keyLength, int reserveSize, String cipherAlgorithm) 464 throws Exception { 465 int keyByteSize = keyLength / 8; // 密鑰字節數 466 int decryptBlockSize = keyByteSize - reserveSize; // 解密塊大小=密鑰字節數-padding填充字節數 467 int nBlock = encryptedBytes.length / keyByteSize;// 計算分段解密的block數,理論上能整除 468 469 try { 470 Cipher cipher = Cipher.getInstance(cipherAlgorithm); 471 cipher.init(Cipher.DECRYPT_MODE, privateKey); 472 473 // 輸出buffer,大小爲nBlock個decryptBlockSize 474 ByteArrayOutputStream outbuf = new ByteArrayOutputStream(nBlock * decryptBlockSize); 475 // 分段解密 476 for (int offset = 0; offset < encryptedBytes.length; offset += keyByteSize) { 477 // block大小: decryptBlock 或 剩餘字節數 478 int inputLen = encryptedBytes.length - offset; 479 if (inputLen > keyByteSize) { 480 inputLen = keyByteSize; 481 } 482 483 // 獲得分段解密結果 484 byte[] decryptedBlock = cipher.doFinal(encryptedBytes, offset, inputLen); 485 // 追加結果到輸出buffer中 486 outbuf.write(decryptedBlock); 487 } 488 489 outbuf.flush(); 490 outbuf.close(); 491 return outbuf.toByteArray(); 492 } catch (NoSuchAlgorithmException e) { 493 throw new Exception(String.format("沒有[%s]此類解密算法", cipherAlgorithm)); 494 } catch (NoSuchPaddingException e) { 495 throw new Exception(String.format("沒有[%s]此類填充模式", cipherAlgorithm)); 496 } catch (InvalidKeyException e) { 497 throw new Exception("無效密鑰"); 498 } catch (IllegalBlockSizeException e) { 499 throw new Exception("解密塊大小不合法"); 500 } catch (BadPaddingException e) { 501 throw new Exception("錯誤填充模式"); 502 } catch (IOException e) { 503 throw new Exception("字節輸出流異常"); 504 } 505 } 506 507 /** 508 * AES加密 509 * 510 * @param plainBytes 511 * 明文字節數組 512 * @param keyBytes 513 * 密鑰字節數組 514 * @param keyAlgorithm 515 * 密鑰算法 516 * @param cipherAlgorithm 517 * 加解密算法 518 * @param IV 519 * 隨機向量 520 * @return 加密後字節數組,不經base64編碼 521 * @throws Exception 522 */ 523 public static byte[] AESEncrypt(byte[] plainBytes, byte[] keyBytes, String keyAlgorithm, String cipherAlgorithm, String IV) 524 throws Exception { 525 try { 526 // AES密鑰長度爲128bit、192bit、256bit,默認爲128bit 527 if (keyBytes.length % 8 != 0 || keyBytes.length < 16 || keyBytes.length > 32) { 528 throw new Exception("AES密鑰長度不合法"); 529 } 530 531 Cipher cipher = Cipher.getInstance(cipherAlgorithm); 532 SecretKey secretKey = new SecretKeySpec(keyBytes, keyAlgorithm); 533 if (StringUtils.trimToNull(IV) != null) { 534 IvParameterSpec ivspec = new IvParameterSpec(IV.getBytes()); 535 cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivspec); 536 } else { 537 cipher.init(Cipher.ENCRYPT_MODE, secretKey); 538 } 539 540 byte[] encryptedBytes = cipher.doFinal(plainBytes); 541 542 return encryptedBytes; 543 } catch (NoSuchAlgorithmException e) { 544 throw new Exception(String.format("沒有[%s]此類加密算法", cipherAlgorithm)); 545 } catch (NoSuchPaddingException e) { 546 throw new Exception(String.format("沒有[%s]此類填充模式", cipherAlgorithm)); 547 } catch (InvalidKeyException e) { 548 throw new Exception("無效密鑰"); 549 } catch (InvalidAlgorithmParameterException e) { 550 throw new Exception("無效密鑰參數"); 551 } catch (BadPaddingException e) { 552 throw new Exception("錯誤填充模式"); 553 } catch (IllegalBlockSizeException e) { 554 throw new Exception("加密塊大小不合法"); 555 } 556 } 557 558 /** 559 * AES解密 560 * 561 * @param encryptedBytes 562 * 密文字節數組,不經base64編碼 563 * @param keyBytes 564 * 密鑰字節數組 565 * @param keyAlgorithm 566 * 密鑰算法 567 * @param cipherAlgorithm 568 * 加解密算法 569 * @param IV 570 * 隨機向量 571 * @return 解密後字節數組 572 * @throws Exception 573 */ 574 public static byte[] AESDecrypt(byte[] encryptedBytes, byte[] keyBytes, String keyAlgorithm, String cipherAlgorithm, String IV) 575 throws Exception { 576 try { 577 // AES密鑰長度爲128bit、192bit、256bit,默認爲128bit 578 if (keyBytes.length % 8 != 0 || keyBytes.length < 16 || keyBytes.length > 32) { 579 throw new Exception("AES密鑰長度不合法"); 580 } 581 582 Cipher cipher = Cipher.getInstance(cipherAlgorithm); 583 SecretKey secretKey = new SecretKeySpec(keyBytes, keyAlgorithm); 584 if (IV != null && StringUtils.trimToNull(IV) != null) { 585 IvParameterSpec ivspec = new IvParameterSpec(IV.getBytes()); 586 cipher.init(Cipher.DECRYPT_MODE, secretKey, ivspec); 587 } else { 588 cipher.init(Cipher.DECRYPT_MODE, secretKey); 589 } 590 591 byte[] decryptedBytes = cipher.doFinal(encryptedBytes); 592 593 return decryptedBytes; 594 } catch (NoSuchAlgorithmException e) { 595 throw new Exception(String.format("沒有[%s]此類加密算法", cipherAlgorithm)); 596 } catch (NoSuchPaddingException e) { 597 throw new Exception(String.format("沒有[%s]此類填充模式", cipherAlgorithm)); 598 } catch (InvalidKeyException e) { 599 throw new Exception("無效密鑰"); 600 } catch (InvalidAlgorithmParameterException e) { 601 throw new Exception("無效密鑰參數"); 602 } catch (BadPaddingException e) { 603 throw new Exception("錯誤填充模式"); 604 } catch (IllegalBlockSizeException e) { 605 throw new Exception("解密塊大小不合法"); 606 } 607 } 608 609 public static void decode(String plain,String sign,String charset, PublicKey hzfPubKey) throws Exception{ 610 byte []signData = KeyUtil.string2bytes(sign, 16); 611 byte[] signBytes = Base64.decodeBase64(signData); 612 // 使用商戶公鑰驗證簽名 613 boolean verifySign = CryptoUtil.verifyDigitalSign(plain.getBytes(charset), signBytes, hzfPubKey, "SHA1WithRSA"); 614 if (verifySign) { 615 System.out.println("success"); 616 }else{ 617 System.out.println("failure"); 618 } 619 } 620 public static void decode2(String plain,String sign,String charset, PublicKey hzfPubKey) throws Exception{ 621 System.out.println(sign.length()); 622 byte[] signBytes = Base64.decodeBase64(sign.getBytes(charset)); 623 // 使用商戶公鑰驗證簽名 624 boolean verifySign = CryptoUtil.verifyDigitalSign(plain.getBytes(charset), signBytes, hzfPubKey, "SHA1WithRSA"); 625 if (verifySign) { 626 System.out.println("success"); 627 }else{ 628 System.out.println("failure"); 629 } 630 } 631 public static byte[] hexString2ByteArr(String hexStr) { 632 return new BigInteger(hexStr, 16).toByteArray(); 633 } 634 public static final byte[] hexStrToBytes(String s) { 635 byte[] bytes; 636 bytes = new byte[s.length() / 2]; 637 for (int i = 0; i < bytes.length; i++) { 638 bytes[i] = (byte) Integer.parseInt(s.substring(2 * i, 2 * i + 2), 16); 639 } 640 return bytes; 641 } 642 /** 643 * 字符數組16進制字符 644 * 645 * @param bytes 646 * @return 647 */ 648 public static String bytes2string(byte[] bytes, int radix) { 649 int size = 2; 650 if (radix == 2) { 651 size = 8; 652 } 653 StringBuilder sb = new StringBuilder(bytes.length * size); 654 for (int i = 0; i < bytes.length; i++) { 655 int integer = bytes[i]; 656 while (integer < 0) { 657 integer = integer + 256; 658 } 659 String str = Integer.toString(integer, radix); 660 sb.append(StringUtils.leftPad(str.toUpperCase(), size, "0")); 661 } 662 return sb.toString(); 663 } 664 665 public static void main(String[] args) throws Exception { 666 PublicKey publicKey = null; 667 PrivateKey privateKey = null; 668 //獲取私鑰 669 privateKey = CryptoUtil.getRSAPrivateKeyByFileSuffix("D://cert//private.pem","pem", null, "RSA"); 670 //獲取公鑰 671 publicKey = CryptoUtil.getRSAPublicKeyByFileSuffix("D://cert//public.pem", "pem", "RSA"); 672 System.out.println("讀取的私鑰:"+privateKey); 673 System.out.println("讀取的公鑰:"+publicKey); 674 } 675 }
控制檯輸出結果:
讀取的私鑰:sun.security.rsa.RSAPrivateCrtKeyImpl@fff05816 讀取的公鑰:Sun RSA public key, 2048 bits modulus: 30352155361112247049303023420825968441063511556566487358373956485006944773551398257671324487561388937350982933590996006918917835477306783114880261383096591901729604794449957707356662262038622235714415672319014898606436696498375107689676577265348959122388532382235612467368418451329595782103970659911528392163885786170603134755166468968487939620387819720026031694626892021929646702745041404121725278045217747484135218828125738622519067039814579552154369394886130771836587225024718009130734917582986728907040272962770508323361317551681311374372344275619882074968240026190384773026535791888298002884088455001552303871327 public exponent: 65537