支付宝二维码脱机认证库测试(linux_x86平台验证)

简介: 支付宝二维码脱机认证库测试(linux_x86平台验证)

最近在调试支付宝给提供的二维码脱机认证库,他们给提供了几个文档和 libposoffline.so库文件。


要想在android或linux上做支持支付宝扫码付的应用,必须会调用他们给的二维码脱机认证库。以下是一个在linux调用成功的例子:


如图:



附上代码,其实很简单,就是 linux下调用so动态库的一个例子:


但也遇到一些问题,如库文件找不到,64位和32位不兼容等。


比较常见的undefined reference问题:


1.dl库


undefined reference to ‘dlerror’
undefined reference to ‘dlopen’
undefined reference to ‘dlerror’


增加-ldl链接选项 (-l是链接选项的前缀)


找不到库的问题:


修改LD_LIBRARY_PATH


export LD_LIBRARY_PATH=/where/you/install/lib:$LD_LIBRARY_PATH


出现wrong ELF class: ELFCLASS32 in Unknown on line这种是32位程序与64位库的冲突问题

那个libcpputil.so应该是在32位系统里编译的,所以拿到64位机器上报了个错。


64位系统可能可以编译,链接运行32位的库和程序,比如添加-m32之类的选项

包含 #include <dlfcn.h> 和调用


handle =dlopen("libposoffline.so",RTLD_NOW)加载动态库
init_pos_verify1 = dlsym(handle,"init_pos_verify"); 
[root@localhost x86]# gcc -m32  demo.c -ldl -lm
[root@localhost x86]# ./a.out
[root@localhost x86]# export LD_LIBRARY_PATH=/home/myshare/x86:$LD_LIBRARY_PATH
[root@localhost x86]# ldconfig
[root@localhost x86]# ./a.out
鍔犺浇妯″潡閿欒 libposoffline.so: wrong ELF class: ELFCLASS32


查看下你的linux的系统情况,库的情况


[root@localhost x86]# uname -a 
Linux localhost.localdomain 2.6.32-220.el6.x86_64 #1 SMP Tue Dec 6 19:48:22 GMT 2011 x86_64 x86_64 x86_64 GNU/Linux
[root@localhost x86]# cat /proc/version
Linux version 2.6.32-220.el6.x86_64 (mockbuild@c6b18n3.bsys.dev.centos.org) (gcc version 4.4.6 20110731 (Red Hat 4.4.6-3) (GCC) ) #1 SMP Tue Dec 6 19:48:22 GMT 2011
[root@localhost x86]# file libposoffline.so
libposoffline.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, not stripped
[root@localhost x86]# ldd libposoffline.so
ldd: 警告: 你没有执行权限  `./libposoffline.so'
        linux-gate.so.1 =>  (0x00e9c000)
        libc.so.6 => /lib/libc.so.6 (0x00110000)
        /lib/ld-linux.so.2 (0x0055e000)
[root@localhost x86]# gcc -m32 -ldl -lm  -Llib  demo.c
[root@localhost x86]# ./a.out
===========准备数据================
============进行POS初始化=============
===========准备数据结束================
===========校验二维码开始================
二维码过期!请提示用户刷新二维码。
二维码校验结束!验证失败,不放行!
===========验证二维码例程 结束================


写成makefile文件如下:


注意程序运行前需要make install 把库拷贝到 usr/lib目录下,否则运行时会找不到动态库


########################################
#makefile
########################################
BINARY= test
CC= gcc
LD= ld
CFLAGS=  -Wall -g -m32
#LDSCRIPT= -lposoffline -ldl -lm
LDSCRIPT=  -ldl -lm 
LDFLAGS= -m32 -Wl,-V -Llib
OBJS=  demo.o
#CFLAGS=-std=c99
.PHONY: clean
all:images
images: $(BINARY).out
$(OBJS):%.o:%.c
        $(CC) -c $(CFLAGS) $< -o $@
%.out: $(OBJS)
        $(CC) -o $(*).out $(OBJS) $(LDFLAGS) $(LDSCRIPT)
install: 
cp libposoffline.so /usr/lib
clean:
        rm -f *.o


注意链接和编译都不能少了-m32参数项 。-lposoffline这个不需要带上。因为不是静态链接,是动态加载的。如果posoffline这个库是静态库,则需要链接。


#include <dlfcn.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include "pos_crypto.h"
#include "demo.h"
//
void *handle = NULL;  
int (*init_pos_verify1)(const char* key_list, const char* card_type_list);
int (*verify_qrcode_v21)(VERIFY_REQUEST_V2* request_v2, 
          VERIFY_RESPONSE_V2* response_v2);
//
char print_buf[1024] = {0};
int hex_string_to_bytes(
  char* hex_string, 
  int hex_string_len, 
  unsigned char* bytes, 
  int bytes_len);
char* bytes_to_hex_string(
  char* print_buf, 
  int print_buf_len, 
  const unsigned char* bytes, 
  int len);
void mock_qrcode(unsigned char* qrcode, int* qrcode_len);
unsigned char hex_of_char(char c);
/**
 * 验证二维码例程
 *
 * 本例程演示了如何使用支付宝离线安全库对二维码进行验证
 * 例程中使用了mock_qrcode函数生成一个合法的二维码,并验证该二维码的有效性
 * 
 * */
void check_qrcode_demo(){
  int ret = 0;
  const char* pos_param = NULL;
  int qrcode_len = 0;
  unsigned char qrcode[512] = {0};
  const char* key_list = KEY_LIST;
  const char* card_type_list = CARD_TYPE_LIST;
  handle =dlopen("libposoffline.so",RTLD_NOW);  
  if (!handle) {  
    printf( "加载模块错误 %s\n", dlerror() );  
    return;  
  }  
  init_pos_verify1 = dlsym(handle,"init_pos_verify");   
  printf("===========准备数据================\n");
  printf("============进行POS初始化=============\n");  
  /**
   * 请在POS启动时执行POS初始化
   * 初始化时请提供
   * 1. 从支付宝处申请得到的秘钥簇 json列表 形式
   * 2. POS机器支持结算的卡类型 json列表 此处以卡类型 【WH000001 ANT00001】 示例
   * 注:支持卡类型【ANT00001】代表支持支付宝公交付款
   */
  ret = init_pos_verify1(key_list, card_type_list);
  if(ret != SUCCESS){
    printf("初始化POS失败!\n");
    switch(ret){
      case ILLEGAL_PARAM:
        printf("初始化参数格式错误!请检查参数是否符合json列表格式且各字段正确。\n");
      break;
      case NO_ENOUGH_MEMORY:
        printf("内存不足,极端错误,请检查程序运行空间是否足够。\n");
      break;
      case SYSTEM_ERROR:
        printf("系统异常!请联系支付宝技术人员。\n");
      break;
      default:
      break;
    }
    return;
  }
  /**
   * mock一个用户传入的二维码数据qrcode
   * 开发者应当从扫码头获取用户离线公交码
   */
  mock_qrcode(qrcode, &qrcode_len);
  /**
   * pos_param中填入商户pos相关信息 至少包括:
   *    - pos_id  (商户下唯一的pos号)
   *    - type    (脱机记录类型,只刷一次闸机计费的场景下,类型为"SINGLE")
   *    - subject (脱机记录标题,建议放入公交路线)
   *    - record_id (记录id,商户下本次脱机记录唯一id号,record_id必须保证商户唯一,建议通过POS,时间等信息拼装)
   * 注意:pos_param的长度不能大于1024字节!
     */
  pos_param = "{\"pos_id\":\"sh001\",\"type\":\"SINGLE\",\"subject\":\"bus192\",\"record_id\":\"sh001_20160514140218_000001\"}";
  printf("===========准备数据结束================\n");
  printf("===========校验二维码开始================\n");
  //拼装验证请求
  VERIFY_REQUEST_V2 verify_request;
  //装入二进制格式的二维码
  verify_request.qrcode = qrcode;
  //装入二进制二维码长度
  verify_request.qrcode_len = qrcode_len;
  //装入pos_param
  verify_request.pos_param = pos_param;
  //装入本次消费金额 如果生成脱机记录时还无法确定消费金额 装入0(单位:分)
  verify_request.amount_cent = AMOUNT_CENT;
  VERIFY_RESPONSE_V2 verify_response;
  verify_response.uid = (char*)malloc(17);
  verify_response.uid_len = 17;
  verify_response.record = (char*)malloc(2048);
  verify_response.record_len = 2048;
  verify_response.card_no = (char*)malloc(32);
  verify_response.card_no_len = 32;
  verify_response.card_data = (unsigned char*)malloc(128);
  verify_response.card_data_len = 128;
  verify_response.card_type = (char*)malloc(16);
  verify_response.card_type_len = 16;
  /**
   * 调用接口验证二维码的有效性
   */
  verify_qrcode_v21 =  dlsym(handle,"verify_qrcode_v2"); 
  ret = verify_qrcode_v21(&verify_request, &verify_response);
  /**
   * 处理返回的结果
   */
  if(ret != SUCCESS){
    switch(ret){
      case MALFORMED_QRCODE:
        printf("二维码格式错误!请提示用户二维码错误。\n");
      break;
      case QRCODE_INFO_EXPIRED:
        printf("二维码过期!请提示用户刷新二维码。\n");
      break;
      case QRCODE_KEY_EXPIRED:
        printf("二维码密钥过期!请提示用户联网后刷新二维码再使用。\n");
      break;
      case POS_PARAM_ERROR:
        printf("商户传入的pos_param错误,请检查传入的pos_param。\n");
      break;
      case QUOTA_EXCEEDED:
        printf("单笔额度超限!请提示用户由于额度限制无法过闸机。\n");
      break;
      case NO_ENOUGH_MEMORY:
        printf("内存不足,极端错误,请检查程序运行空间是否足够。\n");
      break;
      case QRCODE_DUPLICATED:
        printf("二维码重复!验证失败。\n");
      break;
      case SYSTEM_ERROR:
        printf("系统异常!请联系支付宝技术人员。\n");
      break;
      default:
      break;
    }
    printf("二维码校验结束!验证失败,不放行!\n");
    printf("===========验证二维码例程 结束================\n");
    free(verify_response.uid);
    free(verify_response.record);
    free(verify_response.card_no);
    free(verify_response.card_data);
    free(verify_response.card_type);
    return;
  }
  printf("从二维码中获取到的uid: %s\n", verify_response.uid);
  printf("验证成功后,返还的脱机记录: %s\n", verify_response.record);
  printf("二维码中的卡类型为: %s\n",verify_response.card_type);
  printf("二维码中的卡号为: %s\n", verify_response.card_no);
  bytes_to_hex_string(print_buf, sizeof(print_buf), 
            verify_response.card_data, verify_response.card_data_len);
  printf("二维码中的二进制卡数据(hex string形式):%s\n", print_buf);
  /**
   * 1.商户可以根据uid判断是否为同一用户重复交易
   */
  /**
   * 2.商户可以根据qrcode判断是否为重复二维码
   *   此判断也可以放在校验二维码前执行,商户可以自行选择
   */
  /**
   * 3.商户需要根据卡类型、卡号、卡数据 综合判断该卡的合法性、以及是否受理该卡
   * 请商户保留 可受理 的脱机记录
   */
  free(verify_response.uid);
  free(verify_response.record);
  free(verify_response.card_no);
  free(verify_response.card_data);
  free(verify_response.card_type);
  printf("验证成功,请放行!\n");
  printf("===========验证二维码例程 结束================\n");
}
/**
 * mock一个用户传入的二维码数据qrcode
 * 此处是使用QRCODE_HEX_DATA mock出的用户二维码数据 
 * 开发者测试时请使用二维码工具生成一个新的QRCODE_HEX_DATA后
 * 装入宏定义中QRCODE_HEX_DATA,再执行mock
 */
void mock_qrcode(unsigned char* qrcode, int* qrcode_len){
  char qrcode_hex[] = QRCODE_HEX_DATA;
  int qrcode_hex_len = strlen(qrcode_hex);
  *qrcode_len = strlen(qrcode_hex)/2;
  hex_string_to_bytes(qrcode_hex, qrcode_hex_len, qrcode, *qrcode_len);
}
/**
* 字节数组转hex格式字符串
* @param print_buf: 十六进制字符串buffer
* @param print_buf_len: 十六进制字符串buffer长度
* @param bytes: 二进制数据
* @param bytes_len: 二进制数据长度
*/
char* bytes_to_hex_string(
  char* print_buf, 
  int print_buf_len, 
  const unsigned char* bytes, 
  int len) {
  int i = 0;
  /**
  * 入参校验
  */ 
  if(print_buf == NULL || bytes == NULL || (len * 2 + 1) > print_buf_len) {
    return NULL;
  }
  for(i = 0; i < len; i++) {
    print_buf[i * 2] = g_hex_map_table[(bytes[i] >> 4) & 0x0F];
    print_buf[i * 2 + 1] = g_hex_map_table[(bytes[i]) & 0x0F];
  }
  /**
  * 填充字符串结束符
  */
  print_buf[i * 2] = '\0';
  /**
  * 返回目标地址
  */
  return print_buf;
}
/**
* hex格式字符串转字节数组
* @param hex_string: 十六进制字符串
* @param hex_string_len: 十六进制字符串长度
* @param bytes: 二进制数据存储空间
* @param bytes_len: 目标空间长度
*/
int hex_string_to_bytes(
  char* hex_string, 
  int hex_string_len, 
  unsigned char* bytes, 
  int bytes_len) {
  int i = 0;
  /**
  * 校验十六进制字符串长度必须偶数,并且目标存储空间必须足够存放转换后的二进制数据
  */
  if((hex_string_len % 2 != 0) || (bytes_len * 2 < hex_string_len)) {
    return -1;
  }
  for(i = 0; i < hex_string_len; i += 2) {
    bytes[i/2] = ((hex_of_char(hex_string[i]) << 4) & 0xF0) | 
          (hex_of_char(hex_string[i + 1]) & 0x0F);
  }
  return 1;
}
/**
* hex格式char转二进制
*/
unsigned char hex_of_char(char c) {
  unsigned char tmp = 0;
  if(c >= '0' && c <= '9') {
    tmp = (c - '0');
  }
  else if(c >= 'A' && c <= 'F') {
    tmp = (c - 'A' + 10);
  }
  else if(c >= 'a' && c <= 'f') {
    tmp = (c - 'a' + 10);
  }
  return tmp;
}
int main(int argc, char** argv) {
  check_qrcode_demo();
  return 0;
}


demo.h文件:


#ifndef DEMO__h
#define DEMO__h
#ifdef __cplusplus
extern "C"
{
#endif
#define SUCCESS                  1
#define MALFORMED_QRCODE        -1
#define QRCODE_INFO_EXPIRED     -2
#define QRCODE_KEY_EXPIRED      -3
#define POS_PARAM_ERROR         -4
#define QUOTA_EXCEEDED          -5
#define NO_ENOUGH_MEMORY        -6
#define SYSTEM_ERROR            -7
#define CARDTYPE_UNSUPPORTED    -8
#define NOT_INITIALIZED         -9
#define ILLEGAL_PARAM           -10
#define PROTO_UNSUPPORTED       -11
#define QRCODE_DUPLICATED   -12
#define TEST_ALIPAY_PUBLIC_KEY  "028B90D7C281AD21B4BA9492C522E39B655890CC41420EB8E8826B28C6DF2D467A"
#define QRCODE_HEX_DATA "02010054323038383130323135303834323333315A2F1CC80A0D0A0D00000000000000000000000003BEDDEA3AAA38BABEA523A6727F066248FCCBEE59CA00165A5748303030303031083030303030303031051234567890463044022063B2600A7327976B326C1E7DC32E675BC8FA8B551117A59D75C371E6A7ACD7440220521D28F6164D7A080F4B4231088C53B119DFACF25651A019C375C051B40098EE0458A680F836303402184CC9C9F567BBA3F8E2B30D7FAF5E03E55FC24CE9AEC8E5B1021806E5F931628C522C378DFBCD99CDEC271432C3D1486DD34F"
#define AMOUNT_CENT 200
#define CARD_TYPE_LIST "[\"WH000001\",\"ANT00001\"]"
#define KEY_LIST "[{\"key_id\":0,\"public_key\":\"028B90D7C281AD21B4BA9492C522E39B655890CC41420EB8E8826B28C6DF2D467A\"},\
            {\"key_id\":1,\"public_key\":\"03F04C74CAD7EC0F2AE93AC51EABCE95D3D3E6F32F71816D7D838308578425F873\"},\
            {\"key_id\":2,\"public_key\":\"0307F46E2C7F40B7B89F11A85C11B0C9374C886132073FAE0BD54A940FAEB21907\"},\
            {\"key_id\":3,\"public_key\":\"034532FF3BEBE61DAC18B7F0D7A201A5080D49F2EA9B256669728A4E8AC9D0DC76\"},\
            {\"key_id\":4,\"public_key\":\"0362650BA9947153AB38D6C1F63D3AFFDF1CBD199A7E3EFDD4F61BC6F33F0F8F76\"},\
            {\"key_id\":5,\"public_key\":\"0268A244029140F693BCA395E5BFA79D6B7B7F1E3D232AFDE2955BAE9A2DBB8E2B\"},\
            {\"key_id\":6,\"public_key\":\"028B90D7C281AD21B4BA9492C522E39B655890CC41420EB8E8826B28C6DF2D467A\"},\
            {\"key_id\":7,\"public_key\":\"03B31505F0622E381E3C53211CD44EB4A3FB35DA7094E5F09FA89D91DCC7165929\"},\
            {\"key_id\":8,\"public_key\":\"021ADB0F0E05A7B9BE0C11153E4D0BC3859F5F73EAE9BEADF04160DE9E4BBF9C74\"},\
            {\"key_id\":9,\"public_key\":\"0255668F6A4CCE5272A7FC77A29902D06E14D939CB50DDC071ACB86B54FB3FCD91\"},\
            {\"key_id\":10,\"public_key\":\"02E740AB065F7976C836B32C324FEC665DF034EE2CBEB3C311C14EA59E4494F5AC\"},\
            {\"key_id\":11,\"public_key\":\"02EF5B9310CC93ADC130D71F605474FDBEF284A1AE5AF7493A3A982AE1031BAAC2\"},\
            {\"key_id\":12,\"public_key\":\"031E0F70A8A5460365F91A7D66620BD9424EAAEBD9CFF54E84CB4257C5B32324D9\"},\
            {\"key_id\":13,\"public_key\":\"02D1BEB9BAC72681B9CECBE7EF369663A04D4487EE20CC10673E12920A01FD4189\"},\
            {\"key_id\":14,\"public_key\":\"02393BF79609919DDDE78FBCD0579C4995B04FA84E74D9802D78BC025B777114B9\"},\
            {\"key_id\":15,\"public_key\":\"03C2A0C0D0163CA194FA6F9DCF71C02154D1ECD9CEB77C297F32CF47AA2C9DF22A\"},\
            {\"key_id\":16,\"public_key\":\"02F27F0CFF4D56D513F427D4274B862C4998B3F03FBC59275E7E0E37EA5E492311\"},\
            {\"key_id\":17,\"public_key\":\"03ECADBF719F9C6539534F376A210486888A89B952E8A421A10D25E4601C667C74\"},\
            {\"key_id\":18,\"public_key\":\"0296BD24657AB0E5D4B7A6A8A0D41E5E722CA3AD791B74C8EC2BBFDBD9D9A6F571\"},\
            {\"key_id\":19,\"public_key\":\"0394657638D9FD20B463AF15F761E0F42E94346D35D8F494445C89AAE7A1FA6838\"},\
            {\"key_id\":20,\"public_key\":\"0366050BC5FFA296753607EEC07B811C2A59FB93F2ED41D30D081797267B8CB191\"},\
            {\"key_id\":21,\"public_key\":\"02878B02CF937EED619B85BAADAC24E408BF84E3C428F7AF4CA8D28628DDE2E36C\"},\
            {\"key_id\":22,\"public_key\":\"02A2E791A0AC515A11AA2AEF7207A91AF9A74A1C22297F107DCDFB8CAB75E65CCA\"},\
            {\"key_id\":23,\"public_key\":\"0375D631050A21B80C3B2443D93804067309D5AD7D22CE1D6771D540BDCD499521\"},\
            {\"key_id\":24,\"public_key\":\"02CCA330425FEEF7B4070BC6F605D5703BE2444BAEE16415484CC0D905A2203B12\"},\
            {\"key_id\":25,\"public_key\":\"02F48FB87407A799198350F83586595C5F10F1978DDD944360D16A8086FBC03368\"},\
            {\"key_id\":26,\"public_key\":\"021964E5C29653C261136F43437C31D2C6A2AC1849CB79829731868E9D2947CE85\"},\
            {\"key_id\":27,\"public_key\":\"0318B0F354FB34B0F024BDB689F647DB5BAADA2D91BCAA66DC514059908DAE3C6B\"},\
            {\"key_id\":28,\"public_key\":\"023A391EE698ACB20AD40D42E3D2A546DC0D998D5BEFB626DEC874CDABADD9963F\"},\
            {\"key_id\":29,\"public_key\":\"025D296816661C34CA0C1E528339B01434A98C6CB149BD99C6AA6F37B65E6086B0\"},\
            {\"key_id\":30,\"public_key\":\"0200238F19D827135A2C194D2B52AD681FF1156196EE654C38BB49A9CB8EBA9F7C\"},\
          {\"key_id\":31,\"public_key\":\"02EA31FB09DD181E6645D5E1827CDE07FC7D23BCD9DFB1C3DECDF6534F0B4713B9\"}]"
static char g_hex_map_table[] = "0123456789ABCDEF";
#ifdef __cplusplus
}
#endif
#endif


pos_crypto.h文件:


#ifndef __POS_CRYPTO_H__
#define __POS_CRYPTO_H__
#ifdef __cplusplus
extern "C" {
#endif
/*
#define SUCCESS          1
#define MALFORMED_QRCODE    -1
#define QRCODE_INFO_EXPIRED   -2
#define QRCODE_KEY_EXPIRED    -3
#define POS_PARAM_ERROR     -4
#define QUOTA_EXCEEDED      -5
#define NO_ENOUGH_MEMORY      -6
#define SYSTEM_ERROR      -7
#define CARDTYPE_UNSUPPORTED  -8
#define NOT_INITIALIZED     -9
#define ILLEGAL_PARAM     -10
#define PROTO_UNSUPPORTED     -11
#define QRCODE_DUPLICATED   -12
#define ANT_BUS_PAY "ANT00001"
*/
/**
*  验证二维码的请求
*  参数:qrcode 格式的二维码信息
*  参数:qrcode_len 二维码长度
*  参数:master_pub_key hex格式的支付宝公钥
    例:"028C452939E766BB17DE9EAE0390F7896545D40C565859C9FBFB1B424974915D86"
*  参数:pos_param json形式的pos信息 长度不能大于2048
    ex:{
        "pos_id":"sh001",
        "type":"SINGLE",
        "subject":"杭州公交190路",
        "record_id":"123456"
      }
*  参数:amount_cent 交易金额 如果无交易金额(如两次过闸机才算交易的情况)就传入0
*/
typedef struct _verify_request{
    const unsigned char* qrcode;
    int qrcode_len;
    const char* master_pub_key;
    const char* pos_param;
  int amount_cent;
}VERIFY_REQUEST;
/**
 * 验证二维码的响应信息
 * @param: uid 存放输出uid的buffer
 * @param: uid_len 输出的uid的buffer长度 不能小于17
 * @param: record 存放输出record的buffer 返还的record是标准字符串信息
 * @param: record_len 存record的buffer的长度 不能小于2048
 */
typedef struct _verify_response{
  char* uid;
  int uid_len;
  char* record;
  int record_len;
}VERIFY_RESPONSE;
/**
*  验证二维码的请求 版本二
*  参数:qrcode 格式的二维码信息
*  参数:qrcode_len 二维码长度
*  参数:pos_param json形式的pos信息 长度不能大于1024
    ex:{
        "pos_id":"sh001",
        "type":"SINGLE",
        "subject":"杭州公交190路",
        "record_id":"123456"
      }
*  参数:amount_cent 交易金额 如果无交易金额(如两次过闸机才算交易的情况)就传入0
*/
typedef struct _verify_request_v2{
    const unsigned char* qrcode;
    int qrcode_len;
    const char* pos_param;
  int amount_cent;
}VERIFY_REQUEST_V2;
/**
 * 验证二维码的响应信息 版本二
 * @param: uid 存放输出uid的buffer
 * @param: uid_len 输出的uid的buffer长度 不能小于17
 * @param: record 存放输出record的buffer 返还的record是标准字符串信息
 * @param: record_len 存record的buffer的长度 不能小于2048
 * @param: card_no 存放输出卡号的buffer
 * @param: card_no_len 存card_no的buffer长度 不能小于17
 * @param: card_data 存放输出卡数据的buffer
 * @param: card_data_len 存card_data的buffer长度 不能小于65
 * @param: card_type 存放输出卡类型的buffer
 * @param: card_type_len 存card_type的buffer长度 不能小于9
 */
typedef struct _verify_response_v2{
  char* uid;
  int uid_len;
  char* record;
  int record_len;
  char* card_no;
  int card_no_len;
  unsigned char* card_data;
  int card_data_len;
  char* card_type;
  int card_type_len;
}VERIFY_RESPONSE_V2;
/**
 * 初始化验证二维码
 * 录入支付宝公钥以及支持的卡类型
 * @param: key_list_json 从支付宝开放网关拉取的秘钥信息,以json形式组织成字符串传入
 *   ex:
    [
      {"key_id":0,"public_key":"02170D3C441AF17AE1010A4095B974BF1FE1EA48FCD65BE060A5AD577ABB885088"},
        {"key_id":1,"public_key":"03410D92CDAB5BC9349731136619A93FC3225DE6B235E839F6BEB41A77B79A0424"},
        ...
      ]
 * @param: card_type_list 可支持的卡类型列表
 * @param:
 *  ex:
    [
      "HZ000001",
      "HZ000002",
      "WH000001"
    ]
 */
int init_pos_verify(const char* key_list, const char* card_type_list);
/**
 * 验证二维码信息 版本二
 * @param:request 验证请求
 * @return: 成功返回 1 失败见错误码
 *
 * */
int verify_qrcode_v2(VERIFY_REQUEST_V2* request_v2, 
          VERIFY_RESPONSE_V2* response_v2);
/**
 * 获取二维码中指定的密钥id
 * @param: qrcode 二进制的二维码信息
 * @return: 成功返回大于等于0的密钥ID 失败见错误码
 *
 * */ 
int get_key_id( const unsigned char* qrcode);
/**
 * 验证二维码信息
 * @param:request 验证请求
 * @return: 成功返回 1 失败见错误码
 *
 * */
int verify_qrcode(VERIFY_REQUEST* request,
        VERIFY_RESPONSE* response);
/**
 * 获取当前so库版本号
 * @return: 返回当前so库版本号
 */
char* get_version();
#ifdef __cplusplus
}
#endif
#endif


相关文章
|
13天前
|
存储 编译器 Linux
动态链接的魔法:Linux下动态链接库机制探讨
本文将深入探讨Linux系统中的动态链接库机制,这其中包括但不限于全局符号介入、延迟绑定以及地址无关代码等内容。
187 19
|
10天前
|
算法 数据挖掘 测试技术
犬类癌症检测(CANDiD)研究:使用独立测试集对1000多只犬进行基于高通量测序的多癌种早期检测"液体活检"血液测试的临床验证
这项研究首次在大规模独立测试集上验证了基于NGS的液体活检在犬类多癌种检测中的应用。该方法具有很高的特异性,可以作为一种新的无创癌症筛查和辅助诊断工具。通过早期发现癌症,有望改善犬类癌症的诊断和管理模式。
36 12
|
2月前
|
机器学习/深度学习 JSON 算法
实例分割笔记(一): 使用YOLOv5-Seg对图像进行分割检测完整版(从自定义数据集到测试验证的完整流程)
本文详细介绍了使用YOLOv5-Seg模型进行图像分割的完整流程,包括图像分割的基础知识、YOLOv5-Seg模型的特点、环境搭建、数据集准备、模型训练、验证、测试以及评价指标。通过实例代码,指导读者从自定义数据集开始,直至模型的测试验证,适合深度学习领域的研究者和开发者参考。
940 3
实例分割笔记(一): 使用YOLOv5-Seg对图像进行分割检测完整版(从自定义数据集到测试验证的完整流程)
|
1月前
|
开发框架 安全 .NET
.NET使用Moq开源模拟库简化单元测试
.NET使用Moq开源模拟库简化单元测试~
|
2月前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
116 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
2月前
|
机器学习/深度学习 JSON 算法
语义分割笔记(二):DeepLab V3对图像进行分割(自定义数据集从零到一进行训练、验证和测试)
本文介绍了DeepLab V3在语义分割中的应用,包括数据集准备、模型训练、测试和评估,提供了代码和资源链接。
328 0
语义分割笔记(二):DeepLab V3对图像进行分割(自定义数据集从零到一进行训练、验证和测试)
|
2月前
|
机器学习/深度学习 算法 PyTorch
目标检测实战(五): 使用YOLOv5-7.0版本对图像进行目标检测完整版(从自定义数据集到测试验证的完整流程)
本文详细介绍了使用YOLOv5-7.0版本进行目标检测的完整流程,包括算法介绍、环境搭建、数据集准备、模型训练、验证、测试以及评价指标。YOLOv5以其高精度、快速度和模型小尺寸在计算机视觉领域受到广泛应用。
1038 0
目标检测实战(五): 使用YOLOv5-7.0版本对图像进行目标检测完整版(从自定义数据集到测试验证的完整流程)
|
2月前
|
缓存 数据挖掘 测试技术
目标检测实战(三):YOLO-Nano训练、测试、验证详细步骤
本文介绍了YOLO-Nano在目标检测中的训练、测试及验证步骤。YOLO-Nano是一个轻量级目标检测模型,使用ShuffleNet-v2作为主干网络,结合FPN+PAN特征金字塔和NanoDet的检测头。文章详细说明了训练前的准备、源代码下载、数据集准备、参数调整、模型测试、FPS测试、VOC-map测试、模型训练、模型测试和验证等步骤,旨在帮助开发者高效实现目标检测任务。
69 0
目标检测实战(三):YOLO-Nano训练、测试、验证详细步骤
|
1月前
|
资源调度 前端开发 JavaScript
React 测试库 React Testing Library
【10月更文挑战第22天】本文介绍了 React Testing Library 的基本概念和使用方法,包括安装、基本用法、常见问题及解决方法。通过代码案例详细解释了如何测试 React 组件,帮助开发者提高应用质量和稳定性。
57 0
|
2月前
|
计算机视觉 异构计算
目标检测实战(四):YOLOV4-Tiny 源码训练、测试、验证详细步骤
这篇文章详细介绍了使用YOLOv4-Tiny进行目标检测的实战步骤,包括下载源码和权重文件、配置编译环境、进行简单测试、训练VOC数据集、生成训练文件、准备训练、开始训练以及多GPU训练的步骤。文章还提供了相应的代码示例,帮助读者理解和实践YOLOv4-Tiny模型的训练和测试过程。
254 0