使用Sign64.dll对海关申报数据加签
- 官方文档
- 第一章控件使用说明
- 第二章接口说明
- 基本操作
- 1. 取卡号
- 2. 取证书号
- 3. 加签
- 返回值说明
- 我自己的使用过程
- JNA代码
- 然后就是我的测试代码
- Maven
- 参考链接
官方文档
第一章控件使用说明
本控件以dll的方式提供,调用时需链接Sign64.dll。本控件适应于64位操作系统。
第二章接口说明
请注意以下事项:
(1)[in,out]类型的参数既为输入参数也为输出参数,在使用时必须给定参数的初始值,空间会根据该值判断调用者开辟的空间是否够大
(2)字符统一采用BYTE类型,即unsigned char,长度为UINT,即unsigned int,输出的字节流建议根据长度来取
(3)指针与缓冲区由外部调用程序做初始化
基本操作
1. 取卡号
项目 | 说明 |
函数原型 | UINT GetCardID(BYTE* szCardID, UINT* nCardIDLen) |
使用前提 | extern “C” _declspec(dllimport) UINT GetCardID(BYTE* szCardID, UINT* nCardIDLen) |
功能简介 | 取卡号,卡号至少分配100字节 |
参数说明 | 【out】szCardID 卡号,以\0结束 |
【in,out】nCardIDLen 卡号长度(该参数输入时不能等于0,必须是szCardID实际开辟的空间大小) |
返回值说明
返回值 | 说明 |
0 | 取卡号成功 |
-1 | 卡初始化错 |
-2 | 取卡号失败 |
2. 取证书号
项目 | 说明 |
函数原型 | UINT GetCertNo(BYTE* szCertNo, UINT* nCertNoLen) |
使用前提 | extern “C” _declspec(dllimport) UINT GetCertNo(BYTE* szCertNo, UINT* nCertNoLen) |
功能简介 | 取证书号,证书号至少分配100字节 |
参数说明 | 【out】szCertNo 证书号,以\0结束 |
【in,out】nCertNoLen 证书号长度(该参数输入时不能等于0,必须是szCertNo实际开辟的空间大小) |
返回值说明
返回值 | 说明 |
0 | 取证书号成功 |
-1 | 卡初始化错 |
-2 | 取证书号失败 |
3. 加签
项目 | 说明 |
函数原型 | UINT Sign(BYTE *src, UINT srcLen, BYTE *sign, UINT signLen, const char * pwd) |
使用前提 | extern “C” _declspec(dllimport) UINT Sign(BYTE *src, UINT srcLen, BYTE sign, UINT signLen, const char * pwd) |
功能简介 | 用加密设备传入报文进行加签 |
参数说明 | 【in】src 待签名的原始数据 |
【in】srcLen 待签名的原始数据的长度 | |
【out】sign 签名数据,至少分配128字节 | |
【in,out】signLen 签名数据长度,应大于128个字节,输入时应等于szSignData实际分配的空间大小 | |
【in】pwd 进行加签的卡密码 |
返回值说明
返回值 | 说明 |
0 | 签名成功 |
-1 | 卡初始化错 |
-2 | 卡口令不正确 |
-3 | 签名失败 |
-4 | PEM编码失败 |
我自己的使用过程
因为我整个web程序使用的是JAVA进行开发,而官方提供的文件是DLL,那么也就意味着我需要用Java去调用DLL,听说过可以使用JNI来调用,但是看了网上的教程,都太复杂了,不太适合我这种只有很短时间用来开发的,后来又发现了一个JNI的框架,名字叫JNA,网上JNA的教程很多,我就不赘述如何使用,主要是记录下我在C++指针踩的坑。
JNA代码
因为一开始没有太理解C++中的指针,所以BYTE*我尝试过很多类型,包括char[] 、String 、byte[],结果都不行,后来使用Memory 来分配一段连续的地址,就类似C语言中的malloc函数。
这个问题倒是解决了,还有个问题是UINT*类型,我一开始想,直接给个int,应该也没啥问题,后来发现,不得行,还是的使用int指针,JNA提供了IntByReference 类表示Int指针,同时JNA还提供了很多常用的指针类型,大概是在com.sun.jna.ptr
包中,有需要的可以看看。
好了,问题解决了,那么我附上代码
import com.sun.jna.Library;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.ptr.IntByReference;
public interface CLibrary extends Library {
CLibrary INSTANCE = Native.loadLibrary("Sign64", CLibrary.class);
/**
* 取卡号<br>
* UINT GetCardID(BYTE* szCardID, UINT* nCardIDLen)
*
* @param szCardID
* 卡号,以\0结束
* @param nCardIDLen
* 卡号长度(该参数输入时不能等于0,必须是szCardID实际开辟的空间大小)
* @return 0 取卡号成功 -1 卡初始化错 -2 取卡号失败
*
*/
int GetCardID(Memory szCardID, IntByReference nCardIDLen);
/**
* 取证书号 <br>
* UINT GetCertNo(BYTE* szCertNo, UINT* nCertNoLen)
*
* @param szCertNo
* 证书号,以\0结束
* @param nCardIDLen
* 证书号长度(该参数输入时不能等于0,必须是szCertNo实际开辟的空间大小)
* @return 0 取证书号成功 -1 卡初始化错 -2 取证书号失败
*
*/
int GetCertNo(Memory szCertNo, IntByReference nCardIDLen);
/**签名
* UINT Sign(BYTE *src, UINT srcLen, BYTE *sign, UINT* signLen, const
* char * pwd)
*
* @param src
* 待签名的原始数据
* @param srcLen
* 待签名的原始数据的长度
* @param sign
* 签名数据,至少分配128字节
* @param signLen
* 签名数据长度,应大于128个字节,输入时应等于szSignData实际分配的空间大小
* @param pwd
* 进行加签的卡密码
* @return 0 签名成功 -1 卡初始化错 -2 卡口令不正确 -3 签名失败 -4 PEM编码失败
*
*/
int Sign(String src, int srcLen, Memory sign, IntByReference signLen, String pwd);
}
然后就是我的测试代码
public static void main(String[] args) {
Memory memory = new Memory(100);
IntByReference intby = new IntByReference(100);
System.out.println("**********************取卡号**********************");
int getCardID = CLibrary.INSTANCE.GetCardID(memory, intby);
System.out.println(getCardID);
System.out.println(intby.getValue());
System.out.println(new String(memory.getByteArray(0, intby.getValue())));
Memory memory1 = new Memory(100);
System.out.println("**********************取证书号**********************");
int getCertNo = CLibrary.INSTANCE.GetCertNo(memory1, intby);
System.out.println("获取状态:" + getCertNo);
System.out.println(intby.getValue());
System.out.println("证书号:" + new String(memory1.getByteArray(0, intby.getValue())));
Memory sign = new Memory(100);
IntByReference intbyReference = new IntByReference(100);
String src = "testsssssss";
System.out.println("**********************数据加签**********************");
int sign2 = CLibrary.INSTANCE.Sign(src, src.length(), sign, intbyReference, "12345678");
System.out.println(sign2);
System.out.println(new String(sign.getByteArray(0, intbyReference.getValue())));
}
Maven
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>4.5.0</version>
</dependency>
写在最后
如果你跟我一样,如果是在对海关申报数据进行加签的话,那么请一定要将海关总署提供的usercard_cert64文件夹下的所有文件放到合适的位置,不然会产生错误。我一开始也是以为只需要Sign64.dll文件,其实不然,都需要。大概文件目录如下
├─paascloud-master
│ │CPUCard_Client64.dll
│ │epEportBasicApp64.dll
│ │EportSMWConfig.xml -----------------------这个xml文件也有用
│ │IKeyAPI.dll
│ │Sign64.dll
│ │SimpleICAPI.dll
│ │SPSecureAPI64.dll
│ │USBCrw.dll
│ │
│ │