常见数字证书类型

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 * Title : CryptoUtil

57 * Description : 加解密工具类

58 * Create on : 2015-05-04

59 *

60 * @author linshangqing@cmbc.com.cn

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 *
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 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

参考:

1、http://blog.csdn.net/zhiyuan411/article/details/39100241

2、https://baike.baidu.com/item/%E6%95%B0%E5%AD%97%E8%AF%81%E4%B9%A6(百度百科,数字证书相关介绍,个人感觉挺好,挺详细的)

Top