失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > Java实现基于国密SM2 SM4生成证书密钥进行字串的加解密

Java实现基于国密SM2 SM4生成证书密钥进行字串的加解密

时间:2021-04-29 05:28:55

相关推荐

Java实现基于国密SM2 SM4生成证书密钥进行字串的加解密

目录

流程说明:DTO层生成证书密钥所需参数封装类最终密文封装类controller层service层serviceImp层加密工具类测试发送生成证书请求发送生成密文请求发送解读密文请求

流程说明:

DTO层

生成证书密钥所需参数封装类

/*** 安全证书生成DTO** @author luce* @date 08月30日 15:17*/@Data@AllArgsConstructor@NoArgsConstructorpublic class CertificateCreate {/*** 国家代码*/private String countryCode;/*** 省份或州*/private String province;/*** 地区*/private String district;/*** 组织*/private String organization;/*** 通用名称*/private String commonName;/*** 证书存储路径*/private String certificateStoragePath;/*** 密钥存储路径*/private String secretKeyStoragePath;}

最终密文封装类

/*** 密文文件** @author luce* @date 08月31日 14:20*/@Data@AllArgsConstructor@NoArgsConstructorpublic class Ciphertext {/*** 签文*/private String sigFile;/*** 加密密钥*/private String encryptionKey;/*** 加密密文*/private String encryptionFile;/*** 发送时间*/private String time;}

controller层

@RestControllerpublic class CipherController {@Autowiredprivate CipherService cipherService;/*** 生成证书和密钥文件** @param create 参数类* @return mon.result.RestInfo<?>* @author luce* @date /9/1 10:12*/@PostMapping("/cipher/certificatepath")public RestInfo<?> createCertificate(@RequestBody CertificateCreate create) throws Exception {return RestUtil.setSuccessMsg("生成成功!", cipherService.createCertificate(create));}/*** 读取证书** @return mon.result.RestInfo<?>* @author luce* @date /9/1 10:12*/@GetMapping("/cipher/certificate")public RestInfo<?> getCert() throws Exception {return RestUtil.setSuccessMsg("读取成功!", cipherService.getCert());}/*** 生成密文:path** @param str报文* @param certFilePath 接收方证书文件路径* @param privateKeyFilePath 发送方密钥文件路径* @return mon.result.RestInfo<?>* @author luce* @date /9/1 10:17*/@PostMapping("/cipher/encryptedpath")public RestInfo<?> encrypted(String str, @RequestHeader("certFilePath") String certFilePath, @RequestHeader("privateKeyFilePath") String privateKeyFilePath) throws Exception {BCECPublicKey receivePublicKey = getPublicKeyByPath(certFilePath);BCECPrivateKey sendPrivateKey = getPrivateKeyByPath(privateKeyFilePath);return RestUtil.setSuccessMsg("生成成功!", cipherService.createCiphertext(str, receivePublicKey, sendPrivateKey));}/*** 生成密文* @author luce* @date /9/3 10:23* @param map str:报文/cert:接收方证书* @return mon.result.RestInfo<?>*/@PostMapping("/cipher/encrypted")public RestInfo<?> encrypted(@RequestBody Map<String, String> map) throws Exception {BCECPublicKey receivePublicKey = getPublicKey(map.get("cert"));BCECPrivateKey sendPrivateKey = cipherService.getPrivateKey();return RestUtil.setSuccessMsg("生成成功!", cipherService.createCiphertext(map.get("str"), receivePublicKey, sendPrivateKey));}/*** 解读密文:path** @param ciphertext 密文* @param certFilePath 发送方证书文件路径* @param privateKeyFilePath 接收方密钥文件路径* @return mon.result.RestInfo<?>* @author luce* @date /9/1 10:18*/@PostMapping("/cipher/unscrambledpath")public RestInfo<?> unscrambled(@RequestBody Ciphertext ciphertext, @RequestHeader("certFilePath") String certFilePath, @RequestHeader("privateKeyFilePath") String privateKeyFilePath) throws Exception {BCECPublicKey sendPublicKey = getPublicKeyByPath(certFilePath);BCECPrivateKey receivePrivateKey = getPrivateKeyByPath(privateKeyFilePath);return RestUtil.setSuccessMsg("读取成功!", cipherService.unscrambledCiphertext(ciphertext, sendPublicKey, receivePrivateKey));}/*** 解读密文** @param ciphertext 密文* @return mon.result.RestInfo<?>* @author luce* @date /9/1 10:18*/@PostMapping("/cipher/unscrambled")public RestInfo<?> unscrambled(@RequestBody Ciphertext ciphertext) throws Exception {BCECPublicKey sendPublicKey = getPublicKey(ciphertext.getCert());BCECPrivateKey receivePrivateKey = cipherService.getPrivateKey();return RestUtil.setSuccessMsg("读取成功!", cipherService.unscrambledCiphertext(ciphertext, sendPublicKey, receivePrivateKey));}}

service层

public interface CipherService {/*** 生成证书和密钥** @param create* @return 保存路径 -String* @author luce* @date /9/1 10:00*/String createCertificate(CertificateCreate create) throws Exception;/*** 生成加密文件** @param str 报文* @param publicKey 接收方公钥* @param privateKey 发送方私钥* @return com.hb56.cipherclient.dto.Ciphertext* @author luce* @date /9/3 8:45*/Ciphertext createCiphertext(String str, BCECPublicKey publicKey, BCECPrivateKey privateKey) throws Exception;/*** 解读密文* @param ciphertext 密文* @param publicKey 发送方公钥* @param privateKey 接收方私钥* @return 报文 -String* @author luce* @date /9/3 9:53*/String unscrambledCiphertext(Ciphertext ciphertext, BCECPublicKey publicKey, BCECPrivateKey privateKey) throws Exception;/*** 读取证书** @return java.lang.String* @author luce* @date /9/3 10:09*/Object getCert() throws Exception;/*** 读取私钥** @return org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey* @author luce* @date /9/3 13:23*/BCECPrivateKey getPrivateKey() throws Exception;

serviceImp层

这层代码会比较多,不过都有注解

@Slf4j@Servicepublic class CipherServiceImp implements CipherService {/*** 生成证书和密钥** @param create* @return 保存路径 -String* @author luce* @date /8/31 14:56*/@Overridepublic String createCertificate(CertificateCreate create) throws Exception {//创建密钥KeyPair keyPair = SM2Util.generateKeyPair();Map<String, String> names = new HashMap<>();// 国家代码names.put(BCStyle.C.getId(), create.getCountryCode());// 省份或州names.put(BCStyle.ST.getId(), create.getProvince());// 地区names.put(BCStyle.L.getId(), create.getDistrict());// 组织names.put(BCStyle.O.getId(), create.getOrganization());// 通用名称names.put(.getId(), create.getCommonName());X500Name x500Name = CommonUtil.buildX500Name(names);SM2X509CertMaker sm2X509CertMaker = new SM2X509CertMaker(keyPair, 525600000, x500Name, new RandomSNAllocator());PKCS10CertificationRequest pkcs10CertificationRequest = CommonUtil.createCSR(x500Name, new SM2PublicKey((BCECPublicKey) keyPair.getPublic()), keyPair.getPrivate(), SIGN_ALGO_SM3WITHSM2);X509Certificate x509Certificate = sm2X509CertMaker.makeRootCACert(pkcs10CertificationRequest.getEncoded());String certStoragePath = "";String secretKeyStoragePath = "";if (StringUtils.hasText(create.getCertificateStoragePath())) {certStoragePath = create.getCertificateStoragePath() + "/safe/certificate.pem";} else {certStoragePath = acquireJarPath() + "safe/certificate.pem";}if (StringUtils.hasText(create.getSecretKeyStoragePath())) {secretKeyStoragePath = create.getCertificateStoragePath() + "/safe/private.key";} else {secretKeyStoragePath = acquireJarPath() + "safe/private.key";}//保存证书文件createCert(x509Certificate, certStoragePath);//保存密钥文件createKeyPair(keyPair, secretKeyStoragePath);return certStoragePath + " and " + secretKeyStoragePath;}/*** 生成密文文件** @param str 明文* @param publicKey 接收方公钥* @param privateKey 发送方私钥* @return com.hb56.cipherclient.dto.Ciphertext* @author luce* @date /9/2 15:46*/@Overridepublic Ciphertext createCiphertext(String str, BCECPublicKey publicKey, BCECPrivateKey privateKey) throws Exception {Security.addProvider(new BouncyCastleProvider());String localDateTime = LocalDateTime.now().toString();//将报文转码 Base64String encodeStr = Base64Encoder.encode(str.getBytes(StandardCharsets.UTF_8));//将时间转码 Base64String encodeTime = Base64Encoder.encode(localDateTime.getBytes(StandardCharsets.UTF_8));//生成随机密钥byte[] key = SM4Util.generateKey();//加签:用发送方的私钥String sigFile = sign(encodeStr, privateKey, encodeTime);//加密:用随机 SM4keyString encodeCiphertext = encryptedDocument(key, encodeStr);//加密随机密钥:用接收方的公钥byte[] encryptsKey = SM2Util.encrypt(publicKey, key);String encodeKey = Base64Encoder.encode(encryptsKey);return new Ciphertext(sigFile, encodeKey, encodeCiphertext, localDateTime, null);}/*** 解读密文** @param ciphertext 密文* @param publicKey 发送方公钥* @param privateKey 接收方私钥* @return 报文 -String* @author luce* @date /9/3 9:53*/@Overridepublic String unscrambledCiphertext(Ciphertext ciphertext, BCECPublicKey publicKey, BCECPrivateKey privateKey) throws Exception {Security.addProvider(new BouncyCastleProvider());//解密String encodeStr = decodeDocument(ciphertext, privateKey);System.out.println("解密后得到的报文:" + encodeStr);//在报文中加入发送时间一起验签String signStr = encodeStr + Base64Encoder.encode(ciphertext.getTime().getBytes(StandardCharsets.UTF_8));System.out.println("验签内容:" + signStr);//验签boolean result = SM2Util.verify(publicKey, signStr.getBytes(StandardCharsets.UTF_8), Base64Decoder.decode(ciphertext.getSignText()));if (!result) {throw new RuntimeException("验签失败!");}return new String(Base64Decoder.decode(encodeStr), StandardCharsets.UTF_8);}/*** 读取证书** @return java.lang.String* @author luce* @date /9/3 10:09*/@Overridepublic String getCert() {File file = new File(acquireJarPath() + "safe/certificate.pem");long filelength = file.length();byte[] filecontent = new byte[(int) filelength];try {FileInputStream in = new FileInputStream(file);in.read(filecontent);in.close();} catch (IOException e) {e.printStackTrace();}return new String(filecontent);}/*** 读取私钥** @return org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey* @author luce* @date /9/3 13:23*/@Overridepublic BCECPrivateKey getPrivateKey() throws Exception {String privateKey = FileUtil.readString(acquireJarPath() + "safe/private.key", CharsetUtil.CHARSET_UTF_8);return BCECUtil.convertPKCS8ToECPrivateKey(BCECUtil.convertECPrivateKeyPEMToPKCS8(privateKey));}/*** 获取jar包中的绝对路径* @author luce* @date /9/7 15:24 * @return java.lang.String*/private String acquireJarPath() {String path = this.getClass().getProtectionDomain().getCodeSource().getLocation().getFile();try {path = .URLDecoder.decode(path, "UTF-8");} catch (java.io.UnsupportedEncodingException ex) {log.error(ex.getLocalizedMessage());}java.io.File jarFile = new java.io.File(path);String jarFilepath = jarFile.getAbsolutePath();int end = jarFilepath.indexOf("target\\");String result = jarFilepath.substring(0, end + 7);return result;}}

加密工具类

/*** 工具类** @author luce* @date 09月01日 13:40*/@Configurationpublic class CipherTool {public static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----";public static final String END_CERT = "-----END CERTIFICATE-----";/*** 生成证书文件** @param x509Certificate 证书* @param certStoragePath 存储路径* @author luce* @date /8/31 15:27*/public static void createCert(X509Certificate x509Certificate, String certStoragePath) throws CertificateEncodingException {FileUtil.del(certStoragePath);//在指定目录生成证书文件FileUtil.newFile(certStoragePath);//证书标题FileUtil.appendUtf8String(BEGIN_CERT, certStoragePath);//分割线FileUtil.appendUtf8String(System.getProperty("line.separator"), certStoragePath);//转Base64码的证书FileUtil.appendUtf8String(Base64Encoder.encode(x509Certificate.getEncoded()), certStoragePath);//分割线FileUtil.appendUtf8String(System.getProperty("line.separator"), certStoragePath);//尾文FileUtil.appendUtf8String(END_CERT, certStoragePath);}/*** 生成密钥文件** @param keyPair 密钥对* @param secretKeyStoragePath 存储路径* @author luce* @date /8/31 15:30*/public static void createKeyPair(KeyPair keyPair, String secretKeyStoragePath) throws InvalidKeyException, IOException {FileUtil.del(secretKeyStoragePath);//生成私钥ECPrivateKeyParameters bcecPrivateKey = (ECPrivateKeyParameters) ECUtil.generatePrivateKeyParameter(keyPair.getPrivate());//生成公钥ECPublicKeyParameters bcecPublicKey = (ECPublicKeyParameters) ECUtil.generatePublicKeyParameter(keyPair.getPublic());//在指定目录生成密钥文件FileUtil.newFile(secretKeyStoragePath);//转PEM格式密钥FileUtil.appendUtf8String(BCECUtil.convertECPrivateKeyPKCS8ToPEM(BCECUtil.convertECPrivateKeyToPKCS8(bcecPrivateKey, bcecPublicKey)), secretKeyStoragePath);}/*** 从证书 Path 读取公钥** @param certFilePath 证书文件路径* @return org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey* @author luce* @date /9/1 14:53*/public static BCECPublicKey getPublicKeyByPath(String certFilePath) throws Exception {X509Certificate sendCert = SM2CertUtil.getX509Certificate(certFilePath);return SM2CertUtil.getBCECPublicKey(sendCert);}/*** 读取公钥** @param receiveCert 证书* @return org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey* @author luce* @date /9/1 14:53*/public static BCECPublicKey getPublicKey(String receiveCert) throws Exception {Security.addProvider(new BouncyCastleProvider());X509Certificate sendCert = SM2CertUtil.getX509Certificate(new ByteArrayInputStream(receiveCert.getBytes(StandardCharsets.UTF_8)));return SM2CertUtil.getBCECPublicKey(sendCert);}/*** 从 Path 读取私钥** @return org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey* @author luce* @date /9/1 14:53*/public static BCECPrivateKey getPrivateKeyByPath(String privateKeyFilePath) throws Exception {String privateKey = FileUtil.readString(privateKeyFilePath, CharsetUtil.CHARSET_UTF_8);return BCECUtil.convertPKCS8ToECPrivateKey(BCECUtil.convertECPrivateKeyPEMToPKCS8(privateKey));}/*** 加签:用发送方的私钥进行加签** @param encodeStrBase64码报文* @param sendPrivateKey 发送方私钥* @param encodeTime发送时间* @return Base64格式签文 -String* @author luce* @date /8/31 14:37*/public static String sign(String encodeStr, BCECPrivateKey sendPrivateKey, String encodeTime) throws CryptoException {String signStr = encodeStr + encodeTime;byte[] encodeSigFile = SM2Util.sign(sendPrivateKey, signStr.getBytes(StandardCharsets.UTF_8));return Base64Encoder.encode(encodeSigFile);}/*** 加密报文** @param key SM4随机密钥* @param encodeStr Base64格式 报文* @return 密文 -String* @author luce* @date /8/31 16:00*/public static String encryptedDocument(byte[] key, String encodeStr) throws Exception {byte[] ciphertext = SM4Util.encrypt_ECB_Padding(key, encodeStr.getBytes(StandardCharsets.UTF_8));return Base64Encoder.encode(ciphertext);}/*** 解密报文** @param ciphertext加密文件* @param bcecPrivateKey 接收方密钥* @return 报文 -byte[]* @author luce* @date /8/31 16:48*/public static String decodeDocument(Ciphertext ciphertext, BCECPrivateKey bcecPrivateKey) throws Exception {//解码密文byte[] decodeCiphertext = Base64Decoder.decode(ciphertext.getEncryptionFile());//解密随机密钥byte[] key = SM2Util.decrypt(SM2Engine.Mode.C1C3C2, bcecPrivateKey, Base64Decoder.decode(ciphertext.getEncryptionKey()));//解密密文byte[] encodeStr = SM4Util.decrypt_ECB_Padding(key, decodeCiphertext);return new String(encodeStr, StandardCharsets.UTF_8);}}

测试

发送生成证书请求

结果

发送生成密文请求

发送解读密文请求

如果觉得《Java实现基于国密SM2 SM4生成证书密钥进行字串的加解密》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。