对传入参数, 按照key首字母降序排序
json序列化后, 进行 sha256 加密, 结果使用base64编码获取hash
hash进行ECCDSA加密
package cn.box365.ipfs.utils;
import com.alibaba.fastjson.JSONObject;
import sun.misc.BASE64Decoder;
import javax.xml.bind.DatatypeConverter;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;
/**
* ECCDSA加签验签工具类
* @author Administrator
*
*/
public class ECDSAUtil {
private static final String SIGNALGORITHMS = "SHA256withECDSA";
private static final String ALGORITHM = "EC";
private static final String SECP256K1 = "secp256k1";
public static final String PRIVATE_KEY_PATH = "\\src\\main\\resources\\pem\\eccprivate_pkcs8.pem";
public static final String PUBLIC_KEY_PATH = "\\src\\main\\resources\\pem\\eccpublic_pkcs8.pem";
public static String HOST_URL;
static {
if (BlackBoxHttpUtil.IF_FORMAL) {
//ipfs正式
HOST_URL = "https://183.223.56.103:8080/send";
} else {
//测试地址
HOST_URL = "https://183.223.56.103:8080/send";
}
}
public static void main(String[] args) throws Exception {
//1. 生成公钥私钥
//生成公钥私钥
KeyPair keyPair1 = getKeyPair();
PublicKey publicKey1 = keyPair1.getPublic();
PrivateKey privateKey1 = keyPair1.getPrivate();
//密钥转16进制字符串
String publicKey = Base64.getEncoder().encodeToString(publicKey1.getEncoded());
String privateKey = Base64.getEncoder().encodeToString(privateKey1.getEncoded());
System.out.println("生成公钥:"+publicKey);
System.out.println("生成私钥:"+privateKey);
//16进制字符串转密钥对象
PrivateKey privateKey2 = getPrivateKey(privateKey);
PublicKey publicKey2 = getPublicKey(publicKey);
//加签验签
String data="需要签名的数据";
String signECDSA = signECDSA(privateKey2, data);
System.out.println("signECDSA签名结果:" + signECDSA);
signECDSA = signECDSA(privateKey2, data);
boolean verifyECDSA = verifyECDSA(publicKey2, signECDSA, data);
System.out.println("验签结果:"+verifyECDSA);
System.out.println();
System.out.println();
/**
* 注意8是整形
序列化: {"address":"t1mq2zk4dtcxm42sx76djtezlgkyp3gbb4gdcidba","amount":"0.3","nonce":8}
hash: 0lVEvbGmgdiWkkk4N4cGXMQiD2C6i00f8Hr0ggwZvpc=
*/
Map<String,Object> map = new HashMap<>();
map.put("address","t1mq2zk4dtcxm42sx76djtezlgkyp3gbb4gdcidba");
map.put("amount","0.3");
map.put("nonce",12);
String jsonString = getDataSortJsonString(map);
System.out.println("1.jsonString:" + jsonString);
String signECDSA1 = signECDSAByPem(jsonString);
System.out.println("2.签名结果:" + signECDSA1);
boolean verifyECDSA1 = verifyECDSAByPem(signECDSA1, jsonString);
System.out.println("验签结果:"+verifyECDSA1);
String result = sendPost(HOST_URL, BlackBoxHttpUtil.buildParamObj(map), signECDSA1);
System.out.println("请求result:"+result);
}
/**
* 向指定 URL 发送POST方法的请求
*
* @param url
* 发送请求的 URL
* @param param
* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, String param, String auth) throws Exception{
PrintWriter out = null;
OutputStream os = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("auth", auth);
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("Content-Type", "application/json");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
os = conn.getOutputStream();
os.write(param.getBytes("utf-8"));
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(conn.getInputStream(),"utf-8"));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
e.printStackTrace();
}
// 使用finally块来关闭输出流、输入流
finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
if (os != null) {
os.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result;
}
/**
* 加签 通过PEM
* @param data 数据
* @return
*/
public static String signECDSAByPem(String data) {
String result = "";
try {
PrivateKey privateKey = getPrivateKeyByPem();
//执行签名
Signature signature = Signature.getInstance(SIGNALGORITHMS);
signature.initSign(privateKey);
signature.update(data.getBytes());
byte[] sign = signature.sign();
return Base64.getEncoder().encodeToString(sign);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 通过pemprivate key
* @return
* @throws Exception
*/
public static PrivateKey getPrivateKeyByPem() throws Exception {
File directory = new File("");//参数为空
String courseFile = directory.getCanonicalPath() ;
String privateKeyPath = courseFile + PRIVATE_KEY_PATH;
BASE64Decoder base64decoder = new BASE64Decoder();
BufferedReader br8 = new BufferedReader(new FileReader(privateKeyPath));
String s = br8.readLine();
String str = "";
s = br8.readLine();
while (s.charAt(0)!= '-'){
str += s + "\r";
s = br8.readLine();
}
byte[] buffer8 =base64decoder.decodeBuffer(str) ;
br8.close();
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer8);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
return keyFactory.generatePrivate(keySpec);
}
/**
* java 对字符串排序, 并返回json数据
* @return
* @throws Exception
*/
public static String getDataSortJsonString(Map<String,Object> data) throws Exception {
Set<String> keySet = data.keySet();
String[] keyArray = keySet.toArray(new String[keySet.size()]);
Arrays.sort(keyArray);
JSONObject jsonObject = new JSONObject(true);
for (String k : keyArray) {
if (k.equals(BlackBoxHttpUtil.FIELD_SIGN) || k.equals(BlackBoxHttpUtil.FIELD_SUCCESS) ) {
continue;
}
jsonObject.put(k,data.get(k));
}
return jsonObject.toJSONString();
}
/**
* 加签
* @param privateKey 私钥
* @param data 数据
* @return
*/
public static String signECDSA(PrivateKey privateKey, String data) {
String result = "";
try {
//执行签名
Signature signature = Signature.getInstance(SIGNALGORITHMS);
signature.initSign(privateKey);
signature.update(data.getBytes());
byte[] sign = signature.sign();
return Base64.getEncoder().encodeToString(sign);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 验签
* @param publicKey 公钥
* @param signed 签名
* @param data 数据
* @return
*/
public static boolean verifyECDSA(PublicKey publicKey, String signed, String data) {
try {
//验证签名
Signature signature = Signature.getInstance(SIGNALGORITHMS);
signature.initVerify(publicKey);
signature.update(data.getBytes());
byte[] hex = Base64.getDecoder().decode(signed);
boolean bool = signature.verify(hex);
// System.out.println("验证:" + bool);
return bool;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 验签
* @param signed 签名
* @param data 数据
* @return
*/
public static boolean verifyECDSAByPem(String signed, String data) {
try {
PublicKey publicKey = getPublicKeyByPem();
//验证签名
Signature signature = Signature.getInstance(SIGNALGORITHMS);
signature.initVerify(publicKey);
signature.update(data.getBytes());
byte[] hex = Base64.getDecoder().decode(signed);
boolean bool = signature.verify(hex);
// System.out.println("验证:" + bool);
return bool;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 从string转private key
* @param key 私钥的字符串
* @return
* @throws Exception
*/
public static PrivateKey getPrivateKey(String key) throws Exception {
byte[] bytes = DatatypeConverter.parseBase64Binary(key);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
return keyFactory.generatePrivate(keySpec);
}
/**
* 从string转publicKey
* @param key 公钥的字符串
* @return
* @throws Exception
*/
public static PublicKey getPublicKey(String key) throws Exception {
byte[] bytes = DatatypeConverter.parseBase64Binary(key);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
return keyFactory.generatePublic(keySpec);
}
/**
* 从string转publicKey
* @return
* @throws Exception
*/
public static PublicKey getPublicKeyByPem() throws Exception {
File directory = new File("");//参数为空
String courseFile = directory.getCanonicalPath() ;
String privateKeyPath = courseFile + PUBLIC_KEY_PATH;
BASE64Decoder base64decoder = new BASE64Decoder();
BufferedReader br8 = new BufferedReader(new FileReader(privateKeyPath));
String s = br8.readLine();
String str = "";
s = br8.readLine();
while (s.charAt(0)!= '-'){
str += s + "\r";
s = br8.readLine();
}
byte[] buffer8 =base64decoder.decodeBuffer(str) ;
br8.close();
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer8);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
return keyFactory.generatePublic(keySpec);
}
/**
* 生成密钥对
* @return
* @throws Exception
*/
public static KeyPair getKeyPair() throws Exception {
ECGenParameterSpec ecSpec = new ECGenParameterSpec(SECP256K1);
KeyPairGenerator kf = KeyPairGenerator.getInstance(ALGORITHM);
kf.initialize(ecSpec, new SecureRandom());
KeyPair keyPair = kf.generateKeyPair();
return keyPair;
}
}
私钥
eccprivate_pkcs8.pem
-----BEGIN ecc private key-----
MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIAaCofgjFSk5g6UMzu
SRLkIKGYeHFAnVKgKIDS0UJUiNbqf7K/boAFsHAPurVp4h+nYxytlfGENeejrq3H
XO7kR4KhgYkDgYYABAFnxEML0ZCwXIXqAOUX3y1dta5b4gLoyQOAUC0W098Fy4Om
B9VF+Bv3TE/ovwKnmoulBlpbVPD8JBkWLuvQQAdKWwD8cuoGM/6EbOyS926ZJ33A
AZviVoY7y+dOf5QgjNKJfLQe9Uqam2h1J9DEVzEttAjr/91eJozihJvsvhVRVqML
Rw==
-----END ecc private key-----
公钥
eccpublic_pkcs8.pem
-----BEGIN ecc public key-----
MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBZ8RDC9GQsFyF6gDlF98tXbWuW+IC
6MkDgFAtFtPfBcuDpgfVRfgb90xP6L8Cp5qLpQZaW1Tw/CQZFi7r0EAHSlsA/HLq
BjP+hGzskvdumSd9wAGb4laGO8vnTn+UIIzSiXy0HvVKmptodSfQxFcxLbQI6//d
XiaM4oSb7L4VUVajC0c=
-----END ecc public key-----