zoukankan      html  css  js  c++  java
  • 常见数字证书类型

    1 数字证书

    1.1 概述

      数字证书就是互联网通讯中标志通讯各方身份信息的一串数字,提供了一种在Internet上验证通信实体身份的方式,数字证书不是数字身份证,而是身份认证机构盖在数字身份证上的一个章或印(或者说加在数字身份证上的一个签名)。它是由权威机构——CA机构,又称为证书授权(Certificate Authority)中心发行的,人们可以在网上用它来识别对方的身份。

    2 证书格式

    2.1 证书格式分类

    分为2大类:密钥库(含私钥,也可能有公钥)和公钥证书(仅含公钥)

     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】个人信息交换语法标准
     特点     :  1、包含私钥、公钥及其证书
                    2、密钥库和私钥用相同密码进行保护
     
     格式     :  BKS
     扩展名  : .bks
     描述     :  Bouncycastle Keystore】密钥库的BC实现版本,provider为BC
     特点     :  基于JCE实现
     
     格式     : UBER
     扩展名  : .ubr
     描述     : 【Bouncycastle UBER Keystore】密钥库的BC更安全实现版本,provider为BC

    2.2.2 证书文件格式【Certificate】 

    格式          :  DER 
    扩展名       :  .cer/.crt/.rsa

    描述          : 【ASN .1 DER】用于存放证书 
    特点          :  不含私钥、二进制

    格式          :  PKCS7 
    扩展名       : .p7b/.p7r 
    描述          : 【PKCS #7】加密信息语法标准

    特点          : 1、p7b以树状展示证书链,不含私钥
                       2、p7r为CA对证书请求签名的回复,只能用于导入

    格式          :  CMS 
    扩展名       :  .p7c/.p7m/.p7s 
    描述          : 【Cryptographic Message Syntax】 
    特点          : 1、p7c只保存证书
                       2、p7m:signature with enveloped data
                       3、p7s:时间戳签名文件
     
    格式          :  PEM
    扩展名       : .pem 
    描述          : 【Printable Encoded Message】 
    特点          : 1、该编码格式在RFC1421中定义,其实PEM是【Privacy-Enhanced Mail】的简写,但他也同样广泛运用于密钥管理
                       2、ASCII文件
                       3、一般基于base 64编码

    格式         :  PKCS10 
    扩展名      : .p10/.csr 
    描述         : 【PKCS #10】公钥加密标准【Certificate Signing Request】
    特点         :  1、证书签名请求文件
                       2、ASCII文件
                       3、CA签名后以p7r文件回复

    格式          :  SPC 
    扩展名      : .pvk/.spc 
    描述          : 【Software Publishing Certificate】 
    特点          :  微软公司特有的双证书文件格式,经常用于代码签名,其中
                      1、pvk用于保存私钥
                      2、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('
    ');
    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('
    ');
    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
    参考:
      2、https://baike.baidu.com/item/%E6%95%B0%E5%AD%97%E8%AF%81%E4%B9%A6(百度百科,数字证书相关介绍,个人感觉挺好,挺详细的)
  • 相关阅读:
    base64和Blob的相互转换
    限制文件上传的大小和尺寸
    git将本地项目提交到github
    vue-cli3创建项目时报错
    运行项目是node-sass报错的解决方法
    classList的使用
    将数组扁平化并去除其中重复数据,最终得到一个升序且不重复的数组
    移动端的图片放大
    js获取url中的参数
    HTML5-canvas
  • 原文地址:https://www.cnblogs.com/xq1314/p/7987216.html
Copyright © 2011-2022 走看看