最近公司需要开发基于UKEY方式的国密加解密,在网上找了一圈只找到唯一的龙脉科技的UEKY接口,也只有寥寥几个。经过一段时间的摸索终于写完测试通过。(使用了海泰方圆厂商提供的ukey,不管是哪个厂商,都是按照gj密码局要求的接口规范开发的,完全可以借鉴)
实现了SM4加解密和SM2加解密以及疏通了UKEY提供的所有JAVA接口。源码有需要的请v lalawangzi1986, 有偿指导。
贴一下测试过程的源码:
import com.sun.jna.*;
import com.sun.jna.ptr.ByteByReference;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.LongByReference;
import com.sun.jna.ptr.PointerByReference;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
public class SKFUtil5 {
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary)
Native.loadLibrary((Platform.isWindows() ? "C:\\Windows\\SysWOW64\\SKFAPI30987.dll" : "/opt/data/workdir/libSKFAPI-arm64.so"),
CLibrary.class);
//设备操作
long SKF_EnumDev(boolean bPresent, ByteByReference szNameList, LongByReference pulSize);
long SKF_ConnectDev(String szName, PointerByReference phDev);
long SKF_DisConnectDev(Pointer hDev);
long SKF_GetDevInfo(Pointer hDev, DEVINFO pDevInfo);
//应用操作
int SKF_EnumApplication(Pointer hDev, ByteByReference szAppName, LongByReference pulSize);
int SKF_CreateApplication(Pointer hDev, String szAppName, String szAdminPin
,int dwAdminPinRetryCount, String szUserPin, int dwUserPinRetryCount,
int dwCreateFileRights, PointerByReference happ);
int SKF_OpenApplication(Pointer hDev, String pappname, PointerByReference happ);
int SKF_CloseApplication(Pointer hDev);
//访问控制
int SKF_ChangeDevAuthKey(Pointer hDev, byte[] pbKeyValue, int ulKeyLen);
int SKF_DevAuth(Pointer hDev, byte[] pbAuthData, int ulLen);
int SKF_ChangePIN(Pointer hApplication, int ulPINType, String oldPIN,String newPIN, IntByReference pulRetryCount);
int SKF_GetPINInfo(Pointer hApplication, int ulPINType, IntByReference pulMaxRetryCount, IntByReference pulRemainRetryCount, IntByReference pbDefaultPin);
int SKF_VerifyPIN(Pointer hApplication, int ulPINType, String szPIN, LongByReference pulRetryCount);
int SKF_UnblockPIN(Pointer hApplication, String szAdminPIN, String szNewUserPIN, IntByReference pulRetryCount);
int SKF_ClearSecueState(Pointer hApplication);
//容器管理
int SKF_CreateContainer(Pointer hApplication, String szContainerName,PointerByReference phContainer);
int SKF_DeleteContainer(Pointer hApplication, String szContainerName);
int SKF_EnumContainer(Pointer hApplication, byte[] szContainerName, IntByReference pulSize);
int SKF_OpenContainer(Pointer hApplication,String szContainerName,PointerByReference phContainer);
int SKF_CloseContainer(Pointer hContainer);
int SKF_GetContainerType(Pointer hContainer, LongByReference pulContainerType);
int SKF_ExportCertificate(Pointer hContainer, boolean bSignFlag, byte[] pbCert, IntByReference pulCertLen);
int SKF_ImportCertificate(Pointer hContainer, boolean bSignFlag, byte[] pbCert, IntByReference pulCertLen);
//密码服务
//加密
int SKF_EncryptInit(Pointer hKey, BLOCKCIPHERPARAM.ByValue EncryptParam);
int SKF_Encrypt(Pointer hKey, byte[] pbData, int ulDataLen, byte[] pbEncryptedData, IntByReference pulEncryptedLen);
int SKF_EncryptUpdate(Pointer hKey, byte[] pbData, int ulDataLen,byte[] pbEncryptedData, IntByReference pulEncryptedLen);
int SKF_EncryptFinal(Pointer hKey, byte[] pbEncryptedData, IntByReference ulEncryptedDataLen);
//解密
int SKF_DecryptInit(Pointer hKey, BLOCKCIPHERPARAM.ByValue DecryptParam);
int SKF_Decrypt(Pointer hKey, byte[] pbEncryptedData, int ulEncryptedLen, byte[] pbData, IntByReference pulDataLen);
int SKF_DecryptFinal(Pointer hKey, byte[] pbDecryptedData, IntByReference pulDecryptedDataLen);
//导出导入
//bSignFlag=TRUE表示导出签名公钥,FALSE表示导出加密公钥
int SKF_ExportPublicKey(Pointer hContainer, boolean bSignFlag, byte[] pbBlob, IntByReference pulBlobLen);
int SKF_GenECCKeyPair(Pointer hContainer, NativeLong ulAlgId, ECCPUBLICKEYBLOB pBlob);
int SKF_DigestInit(Pointer hDev, int ulAlgID, ECCPUBLICKEYBLOB pPubKey, byte[] pucID, int ulIDLen, PointerByReference phHash);
int SKF_Digest(Pointer hHash, byte[] pbData, int ulDataLen, byte[] pbHashData, IntByReference pulHashLen);
int SKF_DigestUpdate(Pointer hHash, byte[] pbData, int ulDataLen);
int SKF_DigestFinal(Pointer hHash, byte[] pHashData, IntByReference pulHashLen);
int SKF_ECCSignData(Pointer hContainer, byte[] pbData, int ulDataLen, ECCSIGNATUREBLOB pSignature);
int SKF_ECCVerify(Pointer hDev, ECCPUBLICKEYBLOB pECCPubKeyBlob, byte[] pbData, int ulDataLen, ECCSIGNATUREBLOB pSignature);
int SKF_ECCExportSessionKey(Pointer hContainer, int ulAlgId, ECCPUBLICKEYBLOB pPubKey, ECCCIPHERBLOB pData, PointerByReference phSessionKey);
int SKF_ImportECCKeyPair(Pointer hContainer, ENVELOPEDKEYBLOB pEnvelopedKeyBlob);
int SKF_ExtECCSign(Pointer hDev, ECCPRIVATEKEYBLOB pECCPriKeyBlob, byte[] pbData, int ulDataLen, ECCSIGNATUREBLOB pSignature);
int SKF_ExtECCVerify(Pointer hDev,ECCPUBLICKEYBLOB pECCPubKeyBlob, byte[] pbData, int ulDataLen, ECCSIGNATUREBLOB pSignature);
int SKF_ExtECCEncrypt(Pointer hDev, ECCPUBLICKEYBLOB pECCPubKeyBlob, byte[] pbPlainText, int ulPlainTextLen, ECCCIPHERBLOB pCipherText);
int SKF_ExtECCDecrypt(Pointer hDev, ECCPRIVATEKEYBLOB pECCPriKeyBlob, ECCCIPHERBLOB pCipherText, byte[] pbPlainText, IntByReference pulPlainTextLen);
//其他操作
int SKF_SetSymmKey(Pointer hDev, byte[] pbKey, int ulAlgID, PointerByReference phKey);
int SKF_SetSymmKey(Pointer hDev, byte[] pbKey, NativeLong ulAlgID, PointerByReference phKey);
public static class VERSION extends Structure {
public int major;
public int minor;
public static class ByReference extends VERSION implements Structure.ByReference {}
public static class ByValue extends VERSION implements Structure.ByValue {}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "major", "minor"});
}
}
public static class DEVINFO extends Structure {
public VERSION Version;
public byte[] Manufacturer = new byte[64];
public byte[] Issuer = new byte[64];
public byte[] Label = new byte[32];
public byte[] SerialNumber = new byte[32];
public VERSION HWVersion;
public VERSION FirmwareVersion;
public int AlgSymCap;
public int AlgAsymCap;
public int AlgHashCap;
public int DevAuthAlgId;
public int TotalSpace;
public int FreeSpace;
public byte[] Reserved = new byte[64];
public static class ByReference extends DEVINFO implements Structure.ByReference {}
public static class ByValue extends DEVINFO implements Structure.ByValue {}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "Version", "Manufacturer", "Issuer", "Label", "SerialNumber"
, "HWVersion", "FirmwareVersion", "AlgSymCap", "AlgAsymCap", "AlgHashCap", "DevAuthAlgId"
, "TotalSpace", "FreeSpace", "Reserved"});
}
}
public static class BLOCKCIPHERPARAM extends Structure {
public byte[] IVS = new byte[32];
public int IVLen = 0;
public int PaddingType = 0;
public int FeedBitLen = 0;
@Override
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "IVS", "IVLen", "PaddingType", "FeedBitLen"});
}
public static class ByReference extends BLOCKCIPHERPARAM implements Structure.ByReference {}
public static class ByValue extends BLOCKCIPHERPARAM implements Structure.ByValue {}
}
public static class ECCPUBLICKEYBLOB extends Structure {
public static final int ECC_MAX_XCOORDINATE_BITS_LEN = 512;
public static final int ECC_MAX_YCOORDINATE_BITS_LEN = 512;
public int BitLen;
public byte[] XCoordinate = new byte[ECC_MAX_XCOORDINATE_BITS_LEN/8];
public byte[] YCoordinate = new byte[ECC_MAX_YCOORDINATE_BITS_LEN/8];
@Override
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "BitLen", "XCoordinate", "YCoordinate"});
}
// public static class ByReference extends ECCPUBLICKEYBLOB implements Structure.ByReference { }
public static class ByValue extends ECCPUBLICKEYBLOB implements Structure.ByValue {}
}
public static class ECCPRIVATEKEYBLOB extends Structure {
public static final int ECC_MAX_MODULUS_BITS_LEN = 512;
public int BitLen;
public byte[] PrivateKey = new byte[ECC_MAX_MODULUS_BITS_LEN/8];
@Override
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "BitLen", "PrivateKey"});
}
public static class ByReference extends ECCPRIVATEKEYBLOB implements Structure.ByReference { }
public static class ByValue extends ECCPRIVATEKEYBLOB implements Structure.ByValue {}
}
public static class ECCCIPHERBLOB extends Structure {
public static final int ECC_MAX_XCOORDINATE_BITS_LEN = 512;
public byte[] XCoordinate = new byte[ECC_MAX_XCOORDINATE_BITS_LEN/8];
public byte[] YCoordinate = new byte[ECC_MAX_XCOORDINATE_BITS_LEN/8];
public byte[] HASH = new byte[32];
public int CipherLen;
public byte[] Cipher = new byte[1];
@Override
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "XCoordinate", "YCoordinate", "HASH", "CipherLen", "Cipher"});
}
public static class ByReference extends ECCCIPHERBLOB implements Structure.ByReference { }
public static class ByValue extends ECCCIPHERBLOB implements Structure.ByValue {}
}
public static class ECCSIGNATUREBLOB extends Structure {
public static final int ECC_MAX_XCOORDINATE_BITS_LEN = 512;
public byte[] r = new byte[ECC_MAX_XCOORDINATE_BITS_LEN/8];
public byte[] s = new byte[ECC_MAX_XCOORDINATE_BITS_LEN/8];
@Override
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "r", "s"});
}
public static class ByReference extends ECCSIGNATUREBLOB implements Structure.ByReference { }
public static class ByValue extends ECCSIGNATUREBLOB implements Structure.ByValue {}
}
public static class ENVELOPEDKEYBLOB extends Structure {
public int Version;
public int ulSymmAlgID;
public int ulBits;
public byte[] cbEncryptedPriKey = new byte[64];
public ECCPUBLICKEYBLOB.ByReference PubKey;
public ECCCIPHERBLOB.ByReference ECCCipherBlob;
@Override
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "Version", "ulSymmAlgID", "ulBits", "cbEncryptedPriKey", "PubKey", "ECCCipherBlob"});
}
public static class ByReference extends ENVELOPEDKEYBLOB implements Structure.ByReference { }
public static class ByValue extends ENVELOPEDKEYBLOB implements Structure.ByValue {}
}
public static class FILEATTRIBUTE extends Structure {
public byte[] FileName = new byte[32];
public int FileSize;
public int ReadRights;
public int WriteRights;
@Override
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "FileName", "FileSize", "ReadRights", "WriteRights"});
}
public static class ByReference extends FILEATTRIBUTE implements Structure.ByReference { }
public static class ByValue extends FILEATTRIBUTE implements Structure.ByValue {}
}
}
public static void close(CLibrary ukey, Pointer p_hdev){
long ret = ukey.SKF_DisConnectDev(p_hdev);
if(ret != 0){
//throw new Exception("SKF_VerifyPIN fail!");
System.out.println("SKF_DisConnectDev fail!");
}
}
public static void main(String[] args) throws Exception {
CLibrary ukey = CLibrary.INSTANCE;
long ret = -1l;
ByteByReference deviceNameList = new ByteByReference();
LongByReference deviceNameListLen = new LongByReference();
ret = ukey.SKF_EnumDev(true, null, deviceNameListLen);
long len = deviceNameListLen.getPointer().getLong(0);
deviceNameListLen.setValue(len);
ret = ukey.SKF_EnumDev(true, deviceNameList, deviceNameListLen);
if(ret != 0l){
System.out.println("未插入USBKey!");
return ;
}
// 指向第一个设备
String deviceName = deviceNameList.getPointer().getString(0);
PointerByReference hDev = new PointerByReference();
ret = ukey.SKF_ConnectDev(deviceName, hDev);
if(ret != 0){
System.out.println("连接设备失败");
return ;
}
Pointer p_hdev = hDev.getValue();
CLibrary.DEVINFO pDevInfo = new CLibrary.DEVINFO();
//pDevInfo.clear();
ret = ukey.SKF_GetDevInfo(p_hdev, pDevInfo);
if(ret != 0){
System.out.println("连接设备失败");
return ;
}
String s = new String(pDevInfo.Label);
int APP_NAME_SIZE = 256;
ByteByReference bbr_applist = new ByteByReference();
LongByReference lbr_pulSize = new LongByReference();
//枚举设备中所存在的所有应用
ret = ukey.SKF_EnumApplication(p_hdev, bbr_applist, lbr_pulSize);
len = lbr_pulSize.getPointer().getLong(0);
bbr_applist = new ByteByReference();
lbr_pulSize = new LongByReference();
lbr_pulSize.setValue(len);
ret = ukey.SKF_EnumApplication(p_hdev, bbr_applist, lbr_pulSize);
// Fuck!: bbr_applist最后有个空格!需要去掉!
String app_name = bbr_applist.getPointer().getString(0).trim();
PointerByReference pbr_happ = new PointerByReference();
//打开指定的应用
ret = ukey.SKF_OpenApplication(p_hdev, app_name, pbr_happ);
Pointer p_happ = pbr_happ.getValue();
LongByReference lbr_pulRetryCount = new LongByReference();
ret = ukey.SKF_VerifyPIN(p_happ, 1, "111111", lbr_pulRetryCount);
if(ret != 0){
close(ukey, p_hdev);
throw new Exception("SKF_VerifyPIN fail!");
}
//byte[] szContainerName = new byte[1024];
IntByReference pulSize = new IntByReference();
ret = ukey.SKF_EnumContainer(p_happ, null, pulSize);
int len2 = pulSize.getValue();
pulSize.setValue(len2);
byte[] szContainerName = new byte[len2];
ret = ukey.SKF_EnumContainer(p_happ, szContainerName, pulSize);
String containerNames = new String(szContainerName, 0, pulSize.getValue());
String [] containerNameList = containerNames.split("\0");
// //创建指定容器DB
PointerByReference phContainer = new PointerByReference();
String containerName = "DB";
ret = ukey.SKF_OpenContainer(p_happ, containerName, phContainer);
if(ret != 0){
close(ukey, p_hdev);
throw new Exception("SKF_OpenContainer fail!");
}
Pointer hContainer = phContainer.getValue();
LongByReference pulContainerType = new LongByReference();
ret = ukey.SKF_GetContainerType(hContainer, pulContainerType);
if(ret != 0){
close(ukey, p_hdev);
throw new Exception("SKF_GetContainerType fail!");
}
System.out.println("pulContainerType=" + pulContainerType.getValue());
//下一步导入SM4秘钥
String key = "1234567812345678";
byte[] data = key.getBytes();
//SGD_SMS4_ECB 0x00000401 SMS4 算法 ECB 加密模式
long ulAlgID = 0x00000402;
NativeLong ll = new NativeLong(ulAlgID);
//int algid=1026;
int algid=0x00000402;
PointerByReference phKey = new PointerByReference();
ret = ukey.SKF_SetSymmKey(p_hdev, data, ll, phKey);
if(ret != 0){
close(ukey, p_hdev);
throw new Exception("SKF_SetSymmKey fail!");
}
Pointer hKey = phKey.getValue();
ret = ukey.SKF_CloseApplication(p_happ);
if(ret != 0){
close(ukey, p_hdev);
throw new Exception("SKF_CloseApplication fail!");
}
ret = ukey.SKF_DisConnectDev(p_hdev);
if(ret != 0){
//throw new Exception("SKF_VerifyPIN fail!");
System.out.println("SKF_DisConnectDev fail!");
}
p_happ = null;
}
}