目标:JAVA通过JNA调用USBKey的SKF接口,实现SM2证书的PKCS1格式签名和验证
环境:usbkey型号:龙脉gm3000
skf库:mtoken_gm3000_dky.dll x86版,产品版本 1,1,19,1
开发环境:IDEA 14, JDK1.8x86 (如果使用JDK x64,需要更换64位的skf库)
难点:SKF C 语言接口的某些输入输出参数(如ECCPUBLICKEYBLOB,ECCSIGNATUREBLOB),需要参考skf.h 转换成Java的struct结构
代码:
package com.terry.skf;
import com.terry.skf.struct.*;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.ByteByReference;
import com.sun.jna.ptr.LongByReference;
import com.sun.jna.ptr.PointerByReference;
/**
* Created by Administrator on 2021/12/1 0001.
*/
public interface CLibrary extends Library {
public static final String SKF_DLL_PATH ="D:/Java/program_2021_java/demo_skf_jni/dll/mtoken_gm3000_dky";
//CLibrary INSTANCE = (CLibrary) Native.loadLibrary(SKF_DLL_PATH, CLibrary.class);
CLibrary INSTANCE = (CLibrary) Native.load(SKF_DLL_PATH, CLibrary.class);
int SKF_EnumDev(boolean input, ByteByReference out, LongByReference len);
//int SKF_EnumDev(boolean input, PointerByReference out, LongByReference len);
int SKF_ConnectDev(String input, PointerByReference hDev);
int SKF_EnumApplication(Pointer hDev, ByteByReference szAppName, LongByReference pulSize);
int SKF_OpenApplication(Pointer hDev, String pappname, PointerByReference happ);
int SKF_VerifyPIN(Pointer hApplication, int ulPINType, String szPIN, LongByReference pulRetryCount);
int SKF_EnumContainer(Pointer hApplication, Struct_CONTAINER szContainerName, LongByReference pulSize);
//int SKF_EnumContainer(Pointer hApplication, PointerByReference szContainerName, String pulSize);
//int SKF_EnumContainer(Pointer hApplication, Struct_CONTAINER szContainerName, String pulSize);
int SKF_OpenContainer(Pointer hApplication, String szContainerName, PointerByReference phContainer);
int SKF_GetContainerType(Pointer phContainer, LongByReference pulContainerType);
int SKF_ExportPublicKey(Pointer hContainer, boolean bSignFlag, Struct_ECCPUBLICKEYBLOB pbBlob, LongByReference pulBlobLen);
int SKF_ExportCertificate(Pointer hContainer, boolean bSignFlag, Struct_ECCCERTBLOB pbCert, LongByReference pulCertLen);
int SKF_DigestInit(Pointer hdev, int alg_hash, Struct_ECCPUBLICKEYBLOB ecc_pub, String pubid, int ulIDLen, PointerByReference hHash);
int SKF_Digest(Pointer hHash, String pbData, int ulDataLen, Struct_SM3BLOB pbHashData, LongByReference pulHashLen);
int SKF_Digest(Pointer hHash, byte[] pbData, int ulDataLen, Struct_SM3BLOB pbHashData, LongByReference pulHashLen);
int SKF_Digest(Pointer hHash, byte[] pbData, int ulDataLen, Struct_SM3BLOB pbHashData, int pulHashLen);
int SKF_ECCSignData(Pointer hContainer, Struct_SM3BLOB pbData, int ulDataLen, Struct_ECCSIGNATUREBLOB pSignature);
int SKF_ECCVerify(Pointer hDev, Struct_ECCPUBLICKEYBLOB pECCPubKeyBlob, Struct_SM3BLOB pbData, int ulDataLen, Struct_ECCSIGNATUREBLOB pSignature);
int SKF_DisConnectDev(Pointer hDev);
int SKF_CloseContainer(Pointer hcont);
int SKF_CloseApplication(Pointer hApplication);
int SKF_CloseHandle(Pointer hkey);
}
package com.terry.skf;
// https://www.jianshu.com/p/dceae90f8537
import com.terry.skf.struct.*;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.ByteByReference;
import com.sun.jna.ptr.LongByReference;
import com.sun.jna.ptr.PointerByReference;
import com.terry.skf.tool.Util;
import java.util.List;
public class SKF_TOOL {
private static String userid = "1234567812345678";
private Pointer p_hdev = null;
private Pointer p_happ = null;
private Pointer p_hcont = null;
private Pointer p_phHash = null;
private CLibrary ukey = CLibrary.INSTANCE;
private String USER_PIN = "111111";
public SKF_TOOL(String user_pin) {
USER_PIN = user_pin;
int ret = -1 ;
int alg_hash = 1;
int APP_NAME_SIZE = 256;
Util.blue("============SKF_TOOL init...==================");
try{
LongByReference lbr = new LongByReference();
ret = ukey.SKF_EnumDev(true,null,lbr);
long lv = lbr.getPointer().getLong(0);
Util.blue(ret + " SKF_EnumDev 设备编号长度= [" + lv + "]");
if(lv == 0){
System.out.println("未插入USBKey!");
return ;
}
ByteByReference bbr = new ByteByReference();
LongByReference lbr_input = new LongByReference();
lbr_input.setValue(lv);
ret = ukey.SKF_EnumDev(true, bbr, lbr_input);
String str_dev = bbr.getPointer().getString(0);
Util.blue(ret + " SKF_EnumDev 设备编号= [" + str_dev + "]");
PointerByReference lbr_hdev = new PointerByReference();
ret = ukey.SKF_ConnectDev(str_dev, lbr_hdev);
p_hdev = lbr_hdev.getValue();
Util.blue(ret + " SKF_ConnectDev 设备hdev= [" + p_hdev + "]");
ByteByReference bbr_applist = new ByteByReference();
LongByReference lbr_pulSize = new LongByReference();
lbr_pulSize.setValue(APP_NAME_SIZE);
ret = ukey.SKF_EnumApplication(p_hdev, bbr_applist, lbr_pulSize);
// Fuck!: bbr_applist最后有个空格!需要去掉!
String app_name = bbr_applist.getPointer().getString(0).trim();
Util.blue(ret + " SKF_EnumApplication app name= [" + app_name + "]");
PointerByReference pbr_happ = new PointerByReference();
ret = ukey.SKF_OpenApplication(p_hdev, app_name, pbr_happ);
p_happ = pbr_happ.getValue();
Util.blue(ret + " SKF_OpenApplication app handle = [" + p_happ + "]");
LongByReference lbr_pulRetryCount = new LongByReference();
ret = ukey.SKF_VerifyPIN(p_happ, 1, USER_PIN,lbr_pulRetryCount);
Util.blue(ret + " SKF_VerifyPIN 重试次数 = [" + lbr_pulRetryCount.getValue() + "]");
if(ret != 0){
Util.red("SKF_VerifyPIN fail!");
//throw new Exception("SKF_VerifyPIN fail!");
System.out.println("SKF_VerifyPIN fail!");
}
}catch (Exception exp){
exp.printStackTrace();
}
Util.blue("p_hdev =" + p_hdev);
Util.blue("p_happ =" + p_happ);
Util.blue("============SKF_TOOL init end.==================\r\n");
return ;
}
public void close() {
int ret = -1;
Util.blue("\r\n============SKF_TOOL close...==================");
try{
if(p_phHash != null) {
ret = ukey.SKF_CloseHandle(p_phHash);
Util.blue("SKF_CloseHandle " + ret);
}
if(p_hcont != null){
ret = ukey.SKF_CloseContainer(p_hcont);
Util.blue("SKF_CloseContainer " + ret );
}
if(p_happ != null){
ret = ukey.SKF_CloseApplication(p_happ);
Util.blue("SKF_CloseApplication "+ ret );
}
if(p_hdev != null){
ret = ukey.SKF_DisConnectDev(p_hdev);
Util.blue("SKF_DisConnectDev "+ ret );
}
}catch (Exception exp){
exp.printStackTrace();
}
Util.blue("============SKF_TOOL close end.==================");
return ;
}
public String sm3_no_userid(String text_plain) {
return sm3_no_userid( text_plain,"utf-8");
}
public String sm3_no_userid(String text_plain,String charsetName) {
int ret;
String sm3_b64 = "";
int alg_hash = 1;
Util.blue("============SKF_TOOL SM3 Hash_no_userid ...==================");
try {
PointerByReference pbr_phHash = new PointerByReference();
ret = ukey.SKF_DigestInit(p_hdev, alg_hash, null,null,0,pbr_phHash);
p_phHash = pbr_phHash.getValue();
Util.red(ret + " SKF_DigestInit Handle_hash = [" + p_phHash + "]");
LongByReference lbr_pulHashLen = new LongByReference();
ret = ukey.SKF_Digest(p_phHash, text_plain.getBytes(charsetName), text_plain.length(), null, lbr_pulHashLen);
Util.red(ret + " SKF_Digest bbr_pbHashData size = [" + lbr_pulHashLen.getValue() + " bits ]");
Struct_SM3BLOB pbr_pbHashData = new Struct_SM3BLOB();
//lbr_pulHashLen.setValue(32);
ret = ukey.SKF_Digest(p_phHash, text_plain.getBytes(charsetName), text_plain.length(), pbr_pbHashData, lbr_pulHashLen);
sm3_b64 = pbr_pbHashData.get_sm3_b64();
Util.red(ret + " SKF_Digest bbr_pbHashData SM3 Base64 = [" + sm3_b64 + "]");
} catch (Exception exp) {
exp.printStackTrace();
}
Util.blue("============SKF_TOOL SM3 Hash_no_userid end.==================\r\n");
return sm3_b64;
}
public String sm3_with_userid(String text_plain) {
return sm3_with_userid(text_plain,"utf-8");
}
public String sm3_with_userid(String text_plain, String charsetName) {
int ret;
String sm3_b64 = "";
int alg_hash = 1;
Util.blue("============SKF_TOOL SM3 Hash_with_userid ...==================");
try {
Struct_SM3BLOB pbr_pbHashData = sm3_with_userid_ex(text_plain, charsetName);
LongByReference lbr_pulHashLen = new LongByReference();
lbr_pulHashLen.setValue(256);
ret = ukey.SKF_Digest(p_phHash, text_plain.getBytes(charsetName), text_plain.length(), pbr_pbHashData, lbr_pulHashLen);
sm3_b64 = pbr_pbHashData.get_sm3_b64();
Util.red(ret + " SKF_Digest bbr_pbHashData SM3 Base64 = [" + sm3_b64 + "]");
return sm3_b64;
} catch (Exception exp) {
exp.printStackTrace();
}
Util.blue("============SKF_TOOL SM3 Hash_with_userid end.==================\r\n");
return sm3_b64;
}
public Struct_SM3BLOB sm3_with_userid_ex(String text_plain, String charsetName) {
int ret;
String sm3_b64 = "";
int alg_hash = 1;
Struct_SM3BLOB pbr_pbHashData = null;
Util.blue("============SKF_TOOL SM3 Hash_with_userid ...==================");
try {
LongByReference lbr_pulSize = new LongByReference();
ret = ukey.SKF_EnumContainer(p_happ, null, lbr_pulSize);
long pulSize = lbr_pulSize.getValue();
Util.blue(ret + " SKF_EnumContainer 容器名大小 = [" + pulSize + "]");
Struct_CONTAINER containers = new Struct_CONTAINER();
ret = ukey.SKF_EnumContainer(p_happ, containers, lbr_pulSize);
String cont_name = containers.getPointer().getString(0);
Util.blue(ret + " SKF_EnumContainer 容器名 = [" + cont_name + "]");
PointerByReference pbr_phContainer = new PointerByReference();
ret = ukey.SKF_OpenContainer(p_happ, cont_name, pbr_phContainer);
p_hcont = pbr_phContainer.getValue();
Util.blue(ret + " SKF_OpenContainer 容器p_hcont = [" + p_hcont + "]");
LongByReference lbr_pulContainerType = new LongByReference();
ret = ukey.SKF_GetContainerType(p_hcont, lbr_pulContainerType);
long pulContainerType = lbr_pulContainerType.getValue();
Util.blue(ret + " SKF_GetContainerType 容器类型 (0表示未定、尚未分配类型或者为空容器,为1表示为RSA容器,为2表示为ECC容器。)= [" + pulContainerType + "]");
if(pulContainerType == 2){
alg_hash = 2;
}
LongByReference lbr_pulBlobLen = new LongByReference();
ret = ukey.SKF_ExportPublicKey(p_hcont, false, null, lbr_pulBlobLen);
long l_pulBlobLen = lbr_pulBlobLen.getValue();
Util.red(ret + " SKF_ExportPublicKey 公钥大小 = [" + l_pulBlobLen + "]");
Struct_ECCPUBLICKEYBLOB pubkey = new Struct_ECCPUBLICKEYBLOB();
lbr_pulBlobLen.setValue(l_pulBlobLen);
ret = ukey.SKF_ExportPublicKey(p_hcont, false, pubkey, lbr_pulBlobLen);
Util.red(ret + " SKF_ExportPublicKey 公钥 bitlen= " + pubkey.get_BitLen());
Util.red(ret + " SKF_ExportPublicKey 公钥x = [" + Util.bytesToHex(pubkey.XCoordinate) + "]");
Util.red(ret + " SKF_ExportPublicKey 公钥y = [" + Util.bytesToHex(pubkey.YCoordinate) + "]");
PointerByReference pbr_phHash = new PointerByReference();
ret = ukey.SKF_DigestInit(p_hdev, alg_hash, pubkey, userid, userid.length(), pbr_phHash);
p_phHash = pbr_phHash.getValue();
Util.red(ret + " SKF_DigestInit Handle_hash = [" + p_phHash + "]");
LongByReference lbr_pulHashLen = new LongByReference();
ret = ukey.SKF_Digest(p_phHash, text_plain.getBytes(charsetName), text_plain.length(), null, lbr_pulHashLen);
Util.red(ret + " SKF_Digest bbr_pbHashData size = [" + lbr_pulHashLen.getValue() + " bits ]");
pbr_pbHashData = new Struct_SM3BLOB();
ret = ukey.SKF_Digest(p_phHash, text_plain.getBytes(charsetName), text_plain.length(), pbr_pbHashData, lbr_pulHashLen);
sm3_b64 = pbr_pbHashData.get_sm3_b64();
Util.red(ret + " SKF_Digest bbr_pbHashData SM3 Base64 = [" + sm3_b64 + "]");
} catch (Exception exp) {
exp.printStackTrace();
}
Util.blue("============SKF_TOOL SM3 Hash_with_userid end.==================\r\n");
return pbr_pbHashData;
}
public Struct_ECCPUBLICKEYBLOB get_pubkey() {
int ret ;
String cert_p7 = "";
Struct_ECCPUBLICKEYBLOB pubkey = null;
Util.blue("============SKF_TOOL getPubkey ...==================");
try{
LongByReference lbr_pulBlobLen = new LongByReference();
ret = ukey.SKF_ExportPublicKey(p_hcont, false, null, lbr_pulBlobLen);
long l_pulBlobLen = lbr_pulBlobLen.getValue();
Util.red(ret + " SKF_ExportPublicKey 公钥大小 = [" + l_pulBlobLen + "]");
//PointerByReference xxx[] = new PointerByReference[128];
//PointerByReference xxx[] = new PointerByReference[(int)l_pulBlobLen];
pubkey = new Struct_ECCPUBLICKEYBLOB();
lbr_pulBlobLen.setValue(l_pulBlobLen);
ret = ukey.SKF_ExportPublicKey(p_hcont, false, pubkey, lbr_pulBlobLen);
Util.red(ret + " SKF_ExportPublicKey 公钥 bitlen= " + pubkey.get_BitLen());
Util.red(ret + " SKF_ExportPublicKey 公钥x = [" + Util.bytesToHex(pubkey.XCoordinate) + "]");
Util.red(ret + " SKF_ExportPublicKey 公钥y = [" + Util.bytesToHex(pubkey.YCoordinate) + "]");
}catch (Exception exp){
exp.printStackTrace();
}
Util.blue("============SKF_TOOL getPubkey end.==================");
return pubkey;
}
public String get_cert() {
int ret ;
String cert_p7 = "";
try{
LongByReference lbr_pulSize = new LongByReference();
ret = ukey.SKF_EnumContainer(p_happ, null,lbr_pulSize);
long pulSize = lbr_pulSize.getValue();
Util.blue(ret + " SKF_EnumContainer 容器名大小 = [" + pulSize + "]");
Struct_CONTAINER containers= new Struct_CONTAINER();
ret = ukey.SKF_EnumContainer(p_happ, containers,lbr_pulSize);
String cont_name = containers.getPointer().getString(0);
Util.blue(ret + " SKF_EnumContainer 容器名 = [" + cont_name + "]");
PointerByReference pbr_phContainer = new PointerByReference();
ret = ukey.SKF_OpenContainer(p_happ, cont_name,pbr_phContainer);
p_hcont = pbr_phContainer.getValue();
Util.blue(ret + " SKF_OpenContainer 容器p_hcont = [" + p_hcont + "]");
LongByReference lbr_pulCertLen = new LongByReference();
ret = ukey.SKF_ExportCertificate(p_hcont, false, null, lbr_pulCertLen);
int l_pulCertLen = (int)lbr_pulCertLen.getValue();
Util.red(ret + " SKF_ExportCertificate 证书长度xx = [" + l_pulCertLen + "]");
Struct_ECCCERTBLOB pbr_pbCert = new Struct_ECCCERTBLOB.ByReference();
// TRUE表示签名证书,FALSE表示加密证书
ret = ukey.SKF_ExportCertificate(p_hcont, false, pbr_pbCert,lbr_pulCertLen);
cert_p7 = pbr_pbCert.get_cert();
Util.blue(ret + " SKF_ExportCertificate 证书? = [" + cert_p7 + "]");
}catch (Exception exp){
exp.printStackTrace();
}
return cert_p7;
}
public String sign_p1( String text_plain,String USER_PIN) {
return sign_p1( text_plain,"utf-8",USER_PIN);
}
public String sign_p1( String text_plain,String charsetName,String USER_PIN) {
int ret ;
String sign_p1 = "";
int alg_hash = 1;
Util.blue("============SKF_TOOL Sign P1...==================");
try{
Struct_SM3BLOB pbr_pbHashData =sm3_with_userid_ex(text_plain, "utf-8");
Struct_ECCSIGNATUREBLOB pbr_sign = new Struct_ECCSIGNATUREBLOB();
ret = ukey.SKF_ECCSignData(p_hcont,pbr_pbHashData,32 ,pbr_sign);
//Util.blue(ret + " SKF_ECCSignData p1签名长度 = [" + lbr_pulSigLen.getValue() + "]");
sign_p1 = pbr_sign.get_sign();
Util.blue(ret + " SKF_ECCSignData p1签名 = [" + sign_p1 + "]");
}catch (Exception exp){
exp.printStackTrace();
}
Util.blue("============SKF_TOOL Sign P1 end.==================\r\n");
return sign_p1;
}
public int verify_p1( String text_plain,String sign_p1) {
return verify_p1(text_plain,"utf-8", sign_p1);
}
public int verify_p1( String text_plain,String charsetName,String sign_p1) {
int ret = -1;
int ret_verify = -1;
//String sign_p1 = "";
int alg_hash = 1;
Util.blue("============SKF_TOOL Verify P1 ...==================");
try{
Struct_SM3BLOB pbr_pbHashData =sm3_with_userid_ex(text_plain, "utf-8");
Struct_ECCSIGNATUREBLOB pbr_sign = new Struct_ECCSIGNATUREBLOB();
pbr_sign.parse_from_p1(sign_p1);
Struct_ECCPUBLICKEYBLOB pubkey = get_pubkey();
//SKF_ECCVerify(Pointer hDev, Struct_ECCPUBLICKEYBLOB pbData, int ulDataLen, Struct_ECCSIGNATUREBLOB pSignature);
ret = ukey.SKF_ECCVerify(p_hdev, pubkey, pbr_pbHashData,32,pbr_sign);
Util.blue(ret + " SKF_ECCVerify 验证签名 = [" + ret + "]");
ret_verify = ret;
}catch (Exception exp){
exp.printStackTrace();
}
Util.blue("============SKF_TOOL Verify P1 end.==================");
return ret_verify;
}
}
package com.terry.skf.tool;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
/**
* Created by Administrator on 2021/11/30 0030.
*/
public class Util {
public static boolean flag_debug = false;
/**
* 字节数组转16进制
* @param bytes 需要转换的byte数组
* @return 转换后的Hex字符串
*/
public static String bytesToHex(byte[] bytes) {
StringBuffer sb = new StringBuffer();
for(int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(bytes[i] & 0xFF);
if(hex.length() < 2){
sb.append(0);
}
sb.append(hex);
}
return sb.toString();
}
// 使用ArrayList方法
//java 合并两个byte数组
// https://www.cnblogs.com/wisdo/p/5074434.html
//System.arraycopy()方法
public static byte[] byteMerger(byte[] bt1, byte[] bt2){
byte[] bt3 = new byte[bt1.length+bt2.length];
System.arraycopy(bt1, 0, bt3, 0, bt1.length);
System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length);
return bt3;
}
public static void debug(boolean flag) {
//System.out.println("我是一条log");
/* 日志字体颜色 */
flag_debug = flag;
}
public static void red(String args) {
//System.out.println("我是一条log");
/* 日志字体颜色 */
if(flag_debug)
System.out.println(Util.RED+args+Util.RESET);
}
public static void redxx(String args) {
//System.out.println("我是一条log");
/* 日志字体颜色 */
if(flag_debug)
System.out.print(Util.RED+args+Util.RESET);
}
public static void blue(String args) {
//System.out.println("我是一条log");
/* 日志字体颜色 */
if(flag_debug)
System.out.println(Util.BLUE+args+Util.RESET);
}
public static String getString(ByteBuffer buffer)
{
Charset charset = null;
CharsetDecoder decoder = null;
CharBuffer charBuffer = null;
try
{
charset = Charset.forName("UTF-8");
decoder = charset.newDecoder();
// charBuffer = decoder.decode(buffer);//用这个的话,只能输出来一次结果,第二次显示为空
charBuffer = decoder.decode(buffer.asReadOnlyBuffer());
return charBuffer.toString();
}
catch (Exception ex)
{
ex.printStackTrace();
return "";
}
}
// Reset
public static final String RESET = "\033[0m"; // Text Reset
// Regular Colors
public static final String WHITE = "\033[0;30m"; // WHITE
public static final String RED = "\033[0;31m"; // RED
public static final String GREEN = "\033[0;32m"; // GREEN
public static final String YELLOW = "\033[0;33m"; // YELLOW
public static final String BLUE = "\033[0;34m"; // BLUE
public static final String PURPLE = "\033[0;35m"; // PURPLE
public static final String CYAN = "\033[0;36m"; // CYAN
public static final String GREY = "\033[0;37m"; // GREY
// Bold
public static final String WHITE_BOLD = "\033[1;30m"; // WHITE
public static final String RED_BOLD = "\033[1;31m"; // RED
public static final String GREEN_BOLD = "\033[1;32m"; // GREEN
public static final String YELLOW_BOLD = "\033[1;33m"; // YELLOW
public static final String BLUE_BOLD = "\033[1;34m"; // BLUE
public static final String PURPLE_BOLD = "\033[1;35m"; // PURPLE
public static final String CYAN_BOLD = "\033[1;36m"; // CYAN
public static final String GREY_BOLD = "\033[1;37m"; // GREY
// Underline
public static final String WHITE_UNDERLINED = "\033[4;30m"; // WHITE
public static final String RED_UNDERLINED = "\033[4;31m"; // RED
public static final String GREEN_UNDERLINED = "\033[4;32m"; // GREEN
public static final String YELLOW_UNDERLINED = "\033[4;33m"; // YELLOW
public static final String BLUE_UNDERLINED = "\033[4;34m"; // BLUE
public static final String PURPLE_UNDERLINED = "\033[4;35m"; // PURPLE
public static final String CYAN_UNDERLINED = "\033[4;36m"; // CYAN
public static final String GREY_UNDERLINED = "\033[4;37m"; // GREY
// Background
public static final String WHITE_BACKGROUND = "\033[40m"; // WHITE
public static final String RED_BACKGROUND = "\033[41m"; // RED
public static final String GREEN_BACKGROUND = "\033[42m"; // GREEN
public static final String YELLOW_BACKGROUND = "\033[43m"; // YELLOW
public static final String BLUE_BACKGROUND = "\033[44m"; // BLUE
public static final String PURPLE_BACKGROUND = "\033[45m"; // PURPLE
public static final String CYAN_BACKGROUND = "\033[46m"; // CYAN
public static final String GREY_BACKGROUND = "\033[47m"; // GREY
// High Intensity
public static final String WHITE_BRIGHT = "\033[0;90m"; // WHITE
public static final String RED_BRIGHT = "\033[0;91m"; // RED
public static final String GREEN_BRIGHT = "\033[0;92m"; // GREEN
public static final String YELLOW_BRIGHT = "\033[0;93m"; // YELLOW
public static final String BLUE_BRIGHT = "\033[0;94m"; // BLUE
public static final String PURPLE_BRIGHT = "\033[0;95m"; // PURPLE
public static final String CYAN_BRIGHT = "\033[0;96m"; // CYAN
public static final String GREY_BRIGHT = "\033[0;97m"; // GREY
// Bold High Intensity
public static final String WHITE_BOLD_BRIGHT = "\033[1;90m"; // WHITE
public static final String RED_BOLD_BRIGHT = "\033[1;91m"; // RED
public static final String GREEN_BOLD_BRIGHT = "\033[1;92m"; // GREEN
public static final String YELLOW_BOLD_BRIGHT = "\033[1;93m";// YELLOW
public static final String BLUE_BOLD_BRIGHT = "\033[1;94m"; // BLUE
public static final String PURPLE_BOLD_BRIGHT = "\033[1;95m";// PURPLE
public static final String CYAN_BOLD_BRIGHT = "\033[1;96m"; // CYAN
public static final String GREY_BOLD_BRIGHT = "\033[1;97m"; // GREY
// High Intensity backgrounds
public static final String WHITE_BACKGROUND_BRIGHT = "\033[0;100m";// WHITE
public static final String RED_BACKGROUND_BRIGHT = "\033[0;101m";// RED
public static final String GREEN_BACKGROUND_BRIGHT = "\033[0;102m";// GREEN
public static final String YELLOW_BACKGROUND_BRIGHT = "\033[0;103m";// YELLOW
public static final String BLUE_BACKGROUND_BRIGHT = "\033[0;104m";// BLUE
public static final String PURPLE_BACKGROUND_BRIGHT = "\033[0;105m"; // PURPLE
public static final String CYAN_BACKGROUND_BRIGHT = "\033[0;106m"; // CYAN
public static final String GREY_BACKGROUND_BRIGHT = "\033[0;107m"; // GREY
public static void main(String[] args) {
String str = new String();
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
str += args[i];
}
System.out.println(str);
}
}
package com.terry.skf.struct;
import com.sun.jna.Structure;
import java.util.Arrays;
import java.util.List;
// https://www.cnblogs.com/gmhappy/p/11864037.html
public class Struct_ECCPUBLICKEYBLOB extends Structure{
/*
typedef struct Struct_ECCPUBLICKEYBLOB{
ULONG BitLen;
BYTE XCoordinate[ECC_MAX_XCOORDINATE_BITS_LEN/8];
BYTE YCoordinate[ECC_MAX_YCOORDINATE_BITS_LEN/8];
}ECCPUBLICKEYBLOB, *PECCPUBLICKEYBLOB;
*/
public Long BitLen;
public byte[] XCoordinate = new byte[64];
public byte[] YCoordinate = new byte[64];
public static class ByReference extends Struct_ECCPUBLICKEYBLOB implements Structure.ByReference {}
public static class ByValue extends Struct_ECCPUBLICKEYBLOB implements Structure.ByValue {}
public Long get_BitLen() {
return BitLen;
}
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[]{"BitLen", "XCoordinate", "YCoordinate"});
}
}
//public void sayUser(Struct_ECCPUBLICKEYBLOB.ByReference struct);
其他struct结构都类似这个结构。
测试代码:
package test;
// https://www.jianshu.com/p/dceae90f8537
// 功能测试列表:
// 1. 计算 SM3 Hash (无需公钥)
// 2. 计算 SM3 Hash (需要公钥,默认userid=1234567812345678)
// 3. 计算pkcs1 签名 (使用SM3 Hash带公钥算法)
// 4. pkcs1验证签名
// 20211203: 存在问题,原文不能包含中文,否则SM3 Hash,签名结果与xtx不兼容。
import com.terry.skf.SKF_TOOL;
import com.terry.skf.tool.Util;
public class skf_test_demo {
public static void main(String[] args) {
String text_plain = "123测试原文"; // 问题:汉字原文做sm3后的结果,与xtx控件做sm3的结果,不一致!
text_plain = "123test1";
System.out.println("text_plain = " + text_plain);
String USER_PIN = "111111";
Util.debug(false);
SKF_TOOL skf = new SKF_TOOL(USER_PIN);
String[] charsetname = {"Unicode","utf-16","utf-8","gbk","gb2312","GB18030","ASCII","ISO-8859-1"};
for( int i =0;i<charsetname.length;i++){
String sm3_no_userid = skf.sm3_no_userid(text_plain, charsetname[i]);
System.out.println("sm3_no_userid = " + sm3_no_userid + " " + charsetname[i]);
}
String sm3_no_userid = skf.sm3_no_userid(text_plain);
System.out.println("sm3_no_userid = " + sm3_no_userid );
String sm3_with_userid = skf.sm3_with_userid(text_plain);
System.out.println("sm3_with_userid = " + sm3_with_userid);
//String cert = get_cert();
// System.out.println("cert = " + cert);
String sign_p1 = skf.sign_p1(text_plain, USER_PIN);
System.out.println("sign_p1 = " + sign_p1);
long startTime=System.currentTimeMillis(); //获取开始时间
for(int i=0;i<51;i++) {
sign_p1 = skf.sign_p1(text_plain, USER_PIN);
System.out.println(i + " sign_p1 = " + sign_p1);
}
long endTime=System.currentTimeMillis(); //获取结束时间
System.out.println("程序运行时间: "+(endTime-startTime)+"ms");
//text_plain = "123test1篡改了";
//sign_p1 = "MEUCIFQbP1fYfIeQZlYqb8q4qQ0FWPvMS+3zXy50jDC3vpEmAiEAqf4G/Aq2xw6MVsMHP4HsrP7K0PJSedGOdh8qlDPRxv8=";
int verify_p1 = skf.verify_p1( text_plain, sign_p1);
System.out.println("verify_p1 = " + verify_p1);
// 释放ukey资源
skf.close();
}
}
20220308: 补充几个struct结构
package com.terry.skf.struct;
import com.sun.jna.Structure;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Created by Administrator on 2021/12/1 0001.
*/
public class Struct_CONTAINER extends Structure{
public byte[] container = new byte[128];
public static class ByReference extends Struct_CONTAINER implements Structure.ByReference {}
public static class ByValue extends Struct_CONTAINER implements Structure.ByValue {}
public byte[] get_container() {
return container;
}
public List<String> get_containers() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
List<String> ls = new ArrayList<String>();
int j = 0;
for(int i=0;i<container.length;i++){
baos.write(container[i]);
if(container[i] == 0){
//System.out.println(i + " cont[i] = 00" + container[i]);
String temp = new String(baos.toByteArray()).trim();
if(temp.length() > 0){
ls.add(temp);
//System.out.println(j + " temp = " + temp);
j = j+1;
baos.reset();
}
//break;
}
}
return ls;
}
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[]{"container"});
}
}
package com.terry.skf.struct;
import com.sun.jna.Structure;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
// https://www.cnblogs.com/gmhappy/p/11864037.html
public class Struct_ECCCERTBLOB extends Structure{
public byte[] cert = new byte[735];
public static class ByReference extends Struct_ECCCERTBLOB implements Structure.ByReference {}
public static class ByValue extends Struct_ECCCERTBLOB implements Structure.ByValue {}
public String get_cert() {
String cert_b64 = Base64.getEncoder().encodeToString(cert);
return cert_b64;
}
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[]{"cert"});
}
}
//public void sayUser(Struct_ECCPUBLICKEYBLOB.ByReference struct);
package com.terry.skf.struct;
import com.sun.jna.Structure;
import java.util.Arrays;
import java.util.List;
// https://www.cnblogs.com/gmhappy/p/11864037.html
public class Struct_ECCPUBLICKEYBLOB extends Structure{
/*
typedef struct Struct_ECCPUBLICKEYBLOB{
ULONG BitLen;
BYTE XCoordinate[ECC_MAX_XCOORDINATE_BITS_LEN/8];
BYTE YCoordinate[ECC_MAX_YCOORDINATE_BITS_LEN/8];
}ECCPUBLICKEYBLOB, *PECCPUBLICKEYBLOB;
*/
public Long BitLen;
public byte[] XCoordinate = new byte[64];
public byte[] YCoordinate = new byte[64];
public static class ByReference extends Struct_ECCPUBLICKEYBLOB implements Structure.ByReference {}
public static class ByValue extends Struct_ECCPUBLICKEYBLOB implements Structure.ByValue {}
public Long get_BitLen() {
return BitLen;
}
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[]{"BitLen", "XCoordinate", "YCoordinate"});
}
}
//public void sayUser(Struct_ECCPUBLICKEYBLOB.ByReference struct);
package com.terry.skf.struct;
import com.sun.jna.Structure;
import com.terry.skf.tool.Util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
// https://www.cnblogs.com/gmhappy/p/11864037.html
public class Struct_ECCSIGNATUREBLOB extends Structure{
// ECC签名数据结构
/*
typedef struct Struct_ECCSIGNATUREBLOB{
BYTE r[ECC_MAX_XCOORDINATE_BITS_LEN/8];
BYTE s[ECC_MAX_YCOORDINATE_BITS_LEN/8];
} ECCSIGNATUREBLOB, *PECCSIGNATUREBLOB;
*/
public byte[] rb = new byte[32];
public byte[] r = new byte[32];
public byte[] sb = new byte[32];
public byte[] s = new byte[32];
public static class ByReference extends Struct_ECCSIGNATUREBLOB implements Structure.ByReference {}
public static class ByValue extends Struct_ECCSIGNATUREBLOB implements Structure.ByValue {}
public byte[] get_r() {
return r;
}
public byte[] get_s() {
return s;
}
// https://blog.csdn.net/daihuimaozideren/article/details/81072738
// 30 + LEN1 + 02 + LEN2 + 00 (optional) + r + 02 + LEN3 + 00(optional) + s
// 当r或s的第1字节大于0x80时,需要在r或s前加1字节0x00。
public String get_sign() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] h ={48,68};
byte[] r_h = {02,32};
byte[] s_h = {02,32};
byte[] r_h2 = {02,33,00};
byte[] s_h2 = {02,33,00};
boolean flag_r = false;
boolean flag_s = false;
String sign_b64 = "";
if(r[0] < 0){
Util.red("r0 < 0 = " + r[0]);
flag_r = true;
h[1] = 69 ; //{48,69};
}
if(s[0] < 0){
Util.red("s0 < 0 = " + s[0]);
flag_s = true;
h[1] =69 ; //{48,69};
}
if((r[0] < 0) && (s[0] < 0)){
h[1] = 70 ; //{48,69};
}
try {
baos.write(h);
if(flag_r){
byte[] r_temp = Util.byteMerger(r_h2, r);
baos.write(r_temp);
}else{
byte[] r_temp = Util.byteMerger(r_h, r);
baos.write(r_temp);
}
if(flag_s){
byte[] s_temp = Util.byteMerger(s_h2, s);
baos.write(s_temp);
}else{
byte[] s_temp = Util.byteMerger(s_h, s);
baos.write(s_temp);
}
} catch (IOException e) {
e.printStackTrace();
}
//byte[] r_s_temp = Util.byteMerger(r_temp, s_temp);
//byte[] sign = Util.byteMerger(h, r_s_temp);
byte[] sign = baos.toByteArray();
Util.red("baos = " + Util.bytesToHex(sign)) ;
sign_b64 = Base64.getEncoder().encodeToString(sign);
return sign_b64;
}
public int parse_from_p1(String sign_p1_base64) {
if(sign_p1_base64.length() == 0){
return -1;
}
byte[] sign_decoded = Base64.getDecoder().decode(sign_p1_base64);
Util.red("hex sign_p1 = " + Util.bytesToHex(sign_decoded));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] r_temp = new byte[32];
//r0 < 0 = -93
//s0 < 0 = -19
//baos = 3046022100a3402e5a90b05a1f5b559c5c419fd1d4c066f6bc04725ef6804045f3f5e7db32022100ed47788ce825f2b6dea62139e9c6f9adb91c71e0358e5e60b55768e9fbc20aa2
//int len_rs = sign_decoded[1];
//System.out.println("len_rs = " + len_rs);
int leng_r = sign_decoded[3];
Util.red("leng_r = " + leng_r);
// 30 leng_r+leng_s | 02 leng_r(x00 _32_) | 02 leng_s( x00 _32_)
int leng_s = sign_decoded[2 + 1 + leng_r + 2];
Util.red("leng_s = " + leng_s);
for(int i =0; i< 32; i++){
if(leng_r == 32){
baos.write(sign_decoded[4 + i]);
}
if(leng_r == 33){
baos.write(sign_decoded[5 + i]);
}
}
r = baos.toByteArray();
//System.out.println("hex r = " + Util.bytesToHex(r));
Util.red("hex r = " + Util.bytesToHex(r)) ;
baos.reset();
int index_s = sign_decoded.length -32;
for(int i =0; i< 32; i++){
baos.write(sign_decoded[index_s + i]);
}
s = baos.toByteArray();
//System.out.println("hex s = " + Util.bytesToHex(s));
Util.red("hex s = " + Util.bytesToHex(s)) ;
baos.reset();
return 1;
}
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[]{"rb", "r", "sb", "s"});
}
}
//public void sayUser(Struct_ECCPUBLICKEYBLOB.ByReference struct);
package com.terry.skf.struct;
import com.sun.jna.Structure;
import java.util.Arrays;
import java.util.List;
// https://www.cnblogs.com/gmhappy/p/11864037.html
public class Struct_RSAPUBLICKEYBLOB extends Structure{
/*
//RSA公钥交换数据块
typedef struct Struct_RSAPUBLICKEYBLOB{
ULONG AlgID; //算法标识号
ULONG BitLen; //模数的实际位长度,必须是8的倍数
BYTE Modulus[MAX_RSA_MODULUS_LEN]; //模数n=p*q,实际长度为BitLen/8字节
BYTE PublicExponent[MAX_RSA_EXPONENT_LEN]; //公开密钥e, 一般为00010001
} RSAPUBLICKEYBLOB, *PRSAPUBLICKEYBLOB;
*/
public Long AlgID;
public Long BitLen;
public byte[] Modulus = new byte[256];
public byte[] PublicExponent = new byte[4];
public static class ByReference extends Struct_RSAPUBLICKEYBLOB implements Structure.ByReference {}
public static class ByValue extends Struct_RSAPUBLICKEYBLOB implements Structure.ByValue {}
public Long get_AlgID() {
return AlgID;
}
public Long get_BitLen() {
return BitLen;
}
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[]{"AlgID","BitLen", "Modulus", "PublicExponent"});
}
}
//public void sayUser(Struct_ECCPUBLICKEYBLOB.ByReference struct);
package com.terry.skf.struct;
import com.sun.jna.Structure;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
// https://www.cnblogs.com/gmhappy/p/11864037.html
public class Struct_SM3BLOB extends Structure{
public byte[] sm3 = new byte[32];
public static class ByReference extends Struct_SM3BLOB implements Structure.ByReference {}
public static class ByValue extends Struct_SM3BLOB implements Structure.ByValue {}
public byte[] get_sm3() {
return sm3;
}
public String get_sm3_b64() {
String sm3_b64 = Base64.getEncoder().encodeToString(sm3);
return sm3_b64;
}
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[]{"sm3"});
}
}
//public void sayUser(Struct_ECCPUBLICKEYBLOB.ByReference struct);