常見數字證書類型

1 數字證書

1.1 概述

  數字證書就是互聯網通信中標誌通信各方身份信息的一串數字,提供了一種在Internet上驗證通訊實體身份的方式,數字證書不是數字身份證,而是身份認證機構蓋在數字身份證上的一個章或印(或者說加在數字身份證上的一個簽名)。它是由權威機構——CA機構,又稱爲證書受權(Certificate Authority)中心發行的,人們能夠在網上用它來識別對方的身份。java

2 證書格式

2.1 證書格式分類

分爲2大類:密鑰庫(含私鑰,也可能有公鑰)和公鑰證書(僅含公鑰)git

 2.1.1 密鑰庫文件格式【Keystore】

 格式     :  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算法

2.2.2 證書文件格式【Certificate】 

格式          :  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用於保存公鑰 工具

2.3 經常使用證書文件格式

  CA中心廣泛採用的規範是X.509[13]系列和PKCS系列,其中主要應用到了如下規範:

2.3.1 X.509(1993) 

  X.509是由國際電信聯盟(ITU-T)制定的數字證書標準。在X.500確保用戶名稱唯一性的基礎上,X.509爲X.500用戶名稱提供了通訊實體的鑑別機制,並規定了實體鑑別過程當中普遍適用的證書語法和數據接口。 

  X.509的最第一版本公佈於1988年。X.509證書由用戶公共密鑰和用戶標識符組成。此外還包括版本號、證書序列號、CA標識符、簽名算法標識、簽發者名稱、證書有效期等信息。這一標準的最新版本是X.509 v3,它定義了包含擴展信息的數字證書。該版數字證書提供了一個擴展信息字段,用來提供更多的靈活性及特殊應用環境下所需的信息傳送。 

  一個標準的X.509數字證書包含如下一些內容:

  證書的版本信息;
  證書的序列號,每一個證書都有一個惟一的證書序列號;
  證書所使用的簽名算法;
  證書的發行機構名稱,命名規則通常採用X.500格式;
  證書的有效期,通用的證書通常採用UTC時間格式,它的計時範圍爲1950-2049;
  證書全部人的名稱,命名規則通常採用X.500格式;
  證書全部人的公開 密鑰
  證書發行者對證書的簽名。
  

2.3.2 PKCS系列標準 

  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:密碼令牌信息格式標準。 

2.3.3 數字證書文件格式(cer和pfx)的區別

  做爲文件形式存在的證書通常有這幾種格式:
  1.帶有私鑰的證書由Public Key Cryptography Standards #12, PKCS#12標準定義,包含了 公鑰和私鑰的二進制格式的證書形式,以 pfx做爲證書文件後綴名。
  2. 二進制編碼的證書 證書中沒有私鑰,DER 編碼二進制格式的證書文件,以cer做爲證書文件後綴名。
  3.Base64編碼的證書證書中沒有私鑰,BASE64 編碼格式的證書文件,也是以cer做爲證書文件後綴名。
  由定義能夠看出,只有pfx格式的數字證書是包含有私鑰的,cer格式的數字證書裏面只有公鑰沒有私鑰。
 

3 java代碼實現(讀取證書密鑰)

  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
參考:
  二、 https://baike.baidu.com/item/%E6%95%B0%E5%AD%97%E8%AF%81%E4%B9%A6(百度百科,數字證書相關介紹,我的感受挺好,挺詳細的)
相關文章
相關標籤/搜索