zoukankan      html  css  js  c++  java
  • java调用dll/so文件

    大家都知道用C++编写的程序如果用于windows使用则编译为xxx.dll文件,如果是Linux使用则编译为libxxx.so文件。下面将java调用dll/so文件的方法粘出来方便下次使用。此处使用的jna的方式

    jna可以从官方下载,也可以从maven里面去引用,下面是引用代码:

    <dependency>
        <groupId>net.java.dev.jna</groupId>
        <artifactId>jna</artifactId>
        <version>4.2.2</version>
    </dependency>

    先把C++的一段代码粘出来参考。

    #pragma once
    #include <stdint.h>
    #ifdef __linux
    #define _APICALL  
    #define DLL_PUBLIC __attribute__ ((visibility ("default")))
    #else
    #define DLL_PUBLIC 
    #define _APICALL __stdcall
    #endif // __linux
    
    static const int8_t CRYPTTYPE_SM2 = 1;            // 非对称加密,SM2官方推荐模式(256bit加密强度)
    static const int8_t CRYPTTYPE_SM4CBC = 2;        // 对称分组加密,SM4 CBC模式(128bit加密强度)
    enum //错误码
    {
        GMC_ERR_OK = 0,                        //成功
        GMC_ERR_CryptoTypeNotSupport = 1,    //不支持该密码系统
        GMC_ERR_PubKeyLost = 2,                //公钥未设置
        GMC_ERR_PriKeyLost = 3,                //私钥未设置
        GMC_ERR_OperationNotSupportThisCryptoType = 4,        //操作不支持目前的密码系统类型。
        GMC_ERR_SMALLMEMSIZE = 5,            //相关内存长度过小
        GMC_ERR_BADALLOCATE = 6,            //内存分配失败
        GMC_ERR_KEY_LENGTH = 7,                //KEY长度不符合
        GMC_ERR_KEY_FORMAT = 8,                //KEY格式不符合    
        GMC_ERR_PARAM = 87,                    //参数错误
        GMC_ERR_OPENSSL_INTERERR = 100,        //openssl 内部错误
        GMC_ERR_CIPHER = 1000,                //CIPHER相关错误
        GMC_ERR_CIPHERTYPE_NOTSUPPORT = 1001,    //不支持的cipher类型
        GMC_ERR_CIPHER_NOTINIT = 1002,            //未初始化
        GMC_ERR_CIPHER_NOTSETKEY = 1003,        //没有设置KEY
        GMC_ERR_SM2 = 2000,                        //sm2相关错误码
        GMC_ERR_SM2_NOTINIT =2001,                //未初始化
        GMC_ERR_SM2_NOTSETKEY = 2002,            //未设置 公钥或者私钥
    };
    extern "C"
    {
        /*
        函数:GMC_New_CTX
        功能:初始化获取一个指定类型的密码体系。
        参数:
            type:密码系统类型
        返回:成功返回上下文指针,失败返回NULL。如果返回失败这表明不支持type指定的类型。
        Note:在相关使用完成后需要调用GMC_Delete_CTX函数进行释放资源。
        */
        DLL_PUBLIC void*  _APICALL GMC_New_CTX(int8_t type);
        /*
        函数:GMC_Delete_CTX
        功能:释放指定的密码体系上下文
        参数:
            pCtx:指定密码体系上下文
        返回:无
        */
        DLL_PUBLIC void _APICALL GMC_Delete_CTX(void *pCtx);
        /*
        函数:GMC_set_Key
        功能:用于对称加密设置密钥
        参数:
            pKey:密钥(16进制数据的字符串化形式)
        返回指:成功返回0,失败见错误码
        */
        DLL_PUBLIC long _APICALL GMC_set_Key(void *pCtx,const char *pszKey);
        /*
        函数:GMC_ECKEY_set_PublicKey
        功能:椭圆曲线加密系统公钥设置
        参数:
            pszXKey:X坐标(16进制数据的字符串化形式)
            pszYKey:Y坐标(16进制数据的字符串化形式)
        返回:成功返回0,失败见错误码
        */
        DLL_PUBLIC long _APICALL GMC_ECKEY_set_PublicKey(void *pCtx,const char *pszXKey, const char *pszYKey);
        /*
        函数:GMC_ECKEY_set_PrivateKey
        功能:椭圆曲线加解密系统私钥设置
        参数:
            pszXKey:私钥(16进制数据的字符串化形式)
        返回:成功返回0,失败见错误码
        */
        DLL_PUBLIC long _APICALL GMC_ECKEY_set_PrivateKey(void *pCtx,const char *pszKey);
        /*
        函数:GMC_Encrypt
        功能:加密指定数据
        参数:
            pData:被加密数据地址
            cbData:被加密数据长度
            pEncrypttedData[out]:用于保存加密数据的地址(可以与pData内存重叠)
            pcbEncryptted[int][out]:in:pEncrypttedData内存的大小,out:加密后数据的长度
        返回:见错误码
        note:参数pEncrypttedData可以为NULL,如果为NULl则pcbEncryptted参数返回需要长度。
        */
        DLL_PUBLIC long _APICALL GMC_Encrypt(void *pCtx,const unsigned char *pData, uint32_t cbData, unsigned char *pEncrypttedData, uint32_t *pcbEncryptted);
        /*
        函数:GMC_Decrypt
        功能:解密指定数据
        参数:
        pData:被解密数据地址
        cbData:被解密数据长度
        pDecrypttedData[out]:用于保存解密数据的地址(可以与pData内存重叠)
        pcbDecryptted[int][out]:in:pDecrypttedData内存的大小,out:解密后数据的长度
        返回:见错误码
        note:参数pDecrypttedData可以为NULL,如果为NULl则pcbDecryptted参数返回需要长度。
        */
        DLL_PUBLIC long _APICALL GMC_Decrypt(void *pCtx,const unsigned char *pData, uint32_t cbData, unsigned char *pDecrypttedData, uint32_t *pcbDecryptted);
        /*
        函数:GMC_GetLastErrMsg
        功能:获取最后一次错误消息
        参数:无
        返回值:错误消息字串,返回值指针值必定不为NULL
        */
        DLL_PUBLIC const char * _APICALL GMC_GetLastErrMsg();
    }
    View Code

    然后就就介绍java的调用方法。什么引用jna就不说了。

    一、创建一个接口并继承于com.sun.jna.Library(这里只实现了C++的部分方法)

    public interface gmcrypto extends Library {
        gmcrypto INSTANCE = (gmcrypto) Native.loadLibrary("gmcrypto", gmcrypto.class);
    
        /**
         * 初始化获取一个指定类型的密码体系。
         * @param type
         */
        IntByReference GMC_New_CTX(long type);
    
        /**
         * 获取上次的错误信息
         * @return
         */
        String GMC_GetLastErrMsg();
        
        /**
         * 加密,注意加密前先获取长度
         * @param intByReference
         * @param pData
         * @param cbData
         * @param pEncrypttedData
         * @param pcbEncryptted
         * @return
         */
        long GMC_Encrypt(IntByReference intByReference, byte[] pData, int cbData, byte[] pEncrypttedData, IntByReference pcbEncryptted);
    
        /**
         * 释放资源上下文
         * @param intByReference
         */
        void GMC_Delete_CTX(IntByReference intByReference);
    }

    二、在普通主方法中就可以调用了 

    public static void main2(String[] args) {
        IntByReference gm = gmcrypto.INSTANCE.GMC_New_CTX(1);
        if (gm == null) {
            System.err.println("指定密码体系:失败");
        } else {
            /****************解密******************/
            byte[] inByte = Base64.getDecoder().decode("MHYCIFnXBM5gF7OF4VYVmPh+exzQi9ik8dZBAFYs0hKrr8WRAiEArIjXQyOR1vdraQcdv9kG9/NGwVCEJ/UKIGw6gKcrTc0EIABJ7041HF7OLvzcSLvPVWDz3zjKWxOBu91someJ7D1+BA2tOEJsGFtH5rYu2Sxn");
            long res = gmcrypto.INSTANCE.GMC_ECKEY_set_PrivateKey(gm, "C51F66571D5C472E383939D3C8944599D50452F4D8909B0C989C68888C0A1509");
            System.out.println("设置私钥结果:" + res);
    
            IntByReference total = new IntByReference(1);
            res = gmcrypto.INSTANCE.GMC_Decrypt(gm, inByte, inByte.length, null, total);
            System.out.println(res + "	" + total.getValue());
    
            byte[] outByte = new byte[total.getValue()];
            res = gmcrypto.INSTANCE.GMC_Decrypt(gm, inByte, inByte.length, outByte, total);
            byte[] temp=new byte[total.getValue()];
            System.arraycopy(outByte, 0, temp, 0, temp.length);
            outByte=temp;
            
            System.out.println("解密结果:" + res + " 长度:" + outByte.length);
            System.out.println(new String(outByte));
    
            System.out.println("最近错误:" + gmcrypto.INSTANCE.GMC_GetLastErrMsg());
            gmcrypto.INSTANCE.GMC_Delete_CTX(gm);
        }
    
    }

    重要说明:

    1、gmcrypto就代表需要引用的dll/so文件的名称,由于java是跨平台,所以不加后缀,文件名为gmcrypto.dll/libgmcrypto.so

    2、java中可以用IntByReference对象代表指针

    3、windows需要把dll文件放到C:WindowsSystem32路径。Linux需要把so文件放到/lib64。当然要根据情况区分32位和64位的情况

  • 相关阅读:
    我读过的书 编程爱好者
    HarmonyOS ListContainer基础用法
    HarmonyOS ListContainer 读取网络json数组
    HarmonyOS Activity页面跳转
    HarmonyOS ListContainer 图文并排
    HarmonyOS 线性布局练习一 登录页面
    jsonserver 环境搭建及使用方法
    HarmonyOS 真机调试
    在win下设置C语言环境变量
    使用 Eclipse 调试 Java 程序的 10 个技巧
  • 原文地址:https://www.cnblogs.com/duanjt/p/8144139.html
Copyright © 2011-2022 走看看