/** * MOMOSEC Security SDK(MSS) * * This file is part of the Open MSS Project * * Copyright (c) 2019 - V0ld1ron * * The MSS is published by V0ld1ron under the BSD license. You should read and accept the * LICENSE before you use, modify, and/or redistribute this software. * * @author V0ld1ron (projectone .at. immomo.com) * @created 2019 */ package com.immomo.rhizobia.rhizobia_J.crypto; import sun.misc.BASE64Decoder; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; /** * @program: java安全编码实践 * * @description: ECDSA 加验签方法 * * 知识点1: * * 知识点2:同AES加密,之所以没有用base64或16进制处理加密后的内容,是因为在使用base64编码后的内容中,可能存在'+'字符, * '+'字符返回给前端后再返回给后端时,如果不经过处理,会变为' '空格字符, * 所以在对加密内容进行base64编码时,请注意'+'字符 * * @author: V0ld1ron * **/ public class ECDSAUtils { private static ECDSAUtils instance = null; //ECDSA 密钥类型 private String keyAlgorithm = "EC"; //数字签名算法 private String signatureAlgorithm = "SHA256withECDSA"; private String pemPriHead = "-----BEGIN PRIVATE KEY-----\n"; private String pemPriEnd = "-----END PRIVATE KEY-----"; private String pemPubHead = "-----BEGIN PUBLIC KEY-----\n"; private String pemPubEnd = "-----END PUBLIC KEY-----"; private PublicKey publicKey = null; private PrivateKey privateKey = null; public String getKeyAlgorithm() { return keyAlgorithm; } public void setKeyAlgorithm(String keyAlgorithm) { this.keyAlgorithm = keyAlgorithm; } public String getSignatureAlgorithm() { return signatureAlgorithm; } public void setSignatureAlgorithm(String signatureAlgorithm) { this.signatureAlgorithm = signatureAlgorithm; } public String getPemPriHead() { return pemPriHead; } public void setPemPriHead(String pemPriHead) { this.pemPriHead = pemPriHead; } public String getPemPriEnd() { return pemPriEnd; } public void setPemPriEnd(String pemPriEnd) { this.pemPriEnd = pemPriEnd; } public String getPemPubHead() { return pemPubHead; } public void setPemPubHead(String pemPubHead) { this.pemPubHead = pemPubHead; } public String getPemPubEnd() { return pemPubEnd; } public void setPemPubEnd(String pemPubEnd) { this.pemPubEnd = pemPubEnd; } public PublicKey getPublicKey() { return publicKey; } public void setPublicKey(PublicKey publicKey) { this.publicKey = publicKey; } public PrivateKey getPrivateKey() { return privateKey; } public void setPrivateKey(PrivateKey privateKey) { this.privateKey = privateKey; } private ECDSAUtils() { } private ECDSAUtils(String priKeyPath, String pubKeyPath) throws Exception { this.privateKey = getPrivateKey(priKeyPath); this.publicKey = getPublicKey(pubKeyPath); } private ECDSAUtils(PrivateKey privateKey, PublicKey publicKey) throws Exception { this.privateKey = privateKey; this.publicKey = publicKey; } public static ECDSAUtils getInstance() throws Exception { if (null == instance) { synchronized (RSAUtils.class) { if(null == instance) { instance = new ECDSAUtils(); } } } return instance; } public static ECDSAUtils getInstance(String priKeyPath, String pubKeyPath) throws Exception { if (null == instance) { synchronized (RSAUtils.class) { if(null == instance) { instance = new ECDSAUtils(priKeyPath, pubKeyPath); } } } else { instance.privateKey = instance.getPrivateKey(priKeyPath); instance.publicKey = instance.getPublicKey(pubKeyPath); } return instance; } public static ECDSAUtils getInstance(PrivateKey privateKey, PublicKey publicKey) throws Exception { if (null == instance) { synchronized (ECDSAUtils.class) { if(null == instance) { instance = new ECDSAUtils(privateKey, publicKey); } } } else { instance.privateKey = privateKey; instance.publicKey = publicKey; } return instance; } /** * @Description: 签名 * @Param: oriData 待签名数据 * @return: byte[] 数字签名 */ public byte[] sign(String oriData) throws Exception { byte[] data = oriData.getBytes(); // 实例化Signature Signature signature = Signature.getInstance(signatureAlgorithm); // 初始化Signature signature.initSign(privateKey); // 更新 signature.update(data); // 签名 byte[] encrypted= signature.sign(); return encrypted; } /** * @Description: 验签 * @Param: sign 数字签名 * @Param: oriData 原始数据 * @return: boolean 是否通过验签 */ public boolean verify(byte[] sign, String oriData) throws Exception { byte[] data = oriData.getBytes(); // 实例化Signature Signature signature = Signature.getInstance(signatureAlgorithm); // 初始化Signature signature.initVerify(publicKey); // 更新 signature.update(data); return signature.verify(sign); } /** * @Description: 取得私钥 * @Param: keyFile 私钥文件路径(pem格式) * 部分PEM文件的头尾不是"-----BEGIN PRIVATE KEY-----\n" * @return: PrivateKey 私钥 */ public PrivateKey getPrivateKey(String keyFile) throws Exception { File f = new File(keyFile); FileInputStream fis = new FileInputStream(f); DataInputStream dis = new DataInputStream(fis); byte[] keyBytes = new byte[(int) f.length()]; dis.readFully(keyBytes); dis.close(); String temp = new String(keyBytes); String privKeyPEM = temp.replace(pemPriHead, ""); privKeyPEM = privKeyPEM.replace(pemPriEnd, ""); byte[] decoded = new BASE64Decoder().decodeBuffer(privKeyPEM); PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decoded); KeyFactory kf = KeyFactory.getInstance("EC"); return kf.generatePrivate(spec); } /** * @Description: 取得公钥 * @Param: keyFile 公钥文件路径(pem格式) * @return: PublicKey 公钥 */ public PublicKey getPublicKey(String keyFile) throws Exception { File f = new File(keyFile); FileInputStream fis = new FileInputStream(f); DataInputStream dis = new DataInputStream(fis); byte[] keyBytes = new byte[(int) f.length()]; dis.readFully(keyBytes); dis.close(); String temp = new String(keyBytes); String publicKeyPEM = temp.replace(pemPubHead, ""); publicKeyPEM = publicKeyPEM.replace(pemPubEnd, ""); byte[] decoded = new BASE64Decoder().decodeBuffer(publicKeyPEM); X509EncodedKeySpec spec = new X509EncodedKeySpec(decoded); KeyFactory kf = KeyFactory.getInstance("EC"); return kf.generatePublic(spec); } }