/***************************************************************/ | |
// | |
//²Î¼û LPA½Ó¿ÚÎĵµV0.1 SGP.22, ·µ»ØAPDU | |
// | |
/***************************************************************/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <ctype.h> | |
#include <sys/time.h> | |
#include <termios.h> | |
#include "lpa_inner.h" | |
static const unsigned char base64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |
/** | |
* @brief ¿É´òÓ¡×Ö·û´®×ª»»Îª×Ö½ÚÊý¾Ý £¬È磺 | |
"C8329BFD0E01" --> {0xC8, 0x32, 0x9B, 0xFD, 0x0E, 0x01} | |
* @param pSrc Ô´×Ö·û´®Ö¸Õë | |
* @param pDst Ä¿±êÊý¾ÝÖ¸Õë | |
* @param nSrcLength Ô´×Ö·û´®³¤¶È | |
* @return Ä¿±êÊý¾Ý³¤¶È | |
* @note | |
* @warning | |
*/ | |
int string2bytes(const char* pSrc, unsigned char* pDst, int nSrcLength) | |
{ | |
int i=0; | |
//УÑé²ÎÊý | |
if(pSrc == NULL || pDst == NULL || nSrcLength < 0) | |
{ | |
return -1; | |
} | |
for(i = 0; i < nSrcLength; i += 2) | |
{ | |
// Êä³ö¸ß4λ | |
if(*pSrc >= '0' && *pSrc <= '9') | |
{ | |
*pDst = (*pSrc - '0') << 4; | |
} | |
else | |
{ | |
*pDst = ((toupper(*pSrc) - 'A') + 10) << 4; | |
} | |
pSrc++; | |
// Êä³öµÍ4λ | |
if(*pSrc >= '0' && *pSrc <= '9') | |
{ | |
*pDst |= *pSrc - '0'; | |
} | |
else | |
{ | |
*pDst |= (toupper(*pSrc) - 'A') + 10; | |
} | |
pSrc++; | |
pDst++; | |
} | |
// ·µ»ØÄ¿±êÊý¾Ý³¤¶È | |
return nSrcLength / 2; | |
} | |
/** | |
* @brief ×Ö½ÚÊý¾Ýת»»Îª¿É´òÓ¡×Ö·û´® £¬È磺 | |
{0xC8, 0x32, 0x9B, 0xFD, 0x0E, 0x01} --> "C8329BFD0E01" | |
* @param pSrc Ô´Êý¾ÝÖ¸Õë | |
* @param pDst Ä¿±ê×Ö·û´®Ö¸Õë | |
* @param nSrcLength Ô´Êý¾Ý³¤¶È | |
* @return Ä¿±êÊý¾Ý³¤¶È£» | |
* @note | |
* @warning | |
*/ | |
int bytes2string(const unsigned char* pSrc, char* pDst, int nSrcLength) | |
{ | |
const char tab[]="0123456789ABCDEF"; // 0x0-0xfµÄ×Ö·û²éÕÒ±í | |
int i = 0; | |
//УÑé²ÎÊý | |
if(pSrc == NULL || pDst == NULL || nSrcLength < 0) | |
{ | |
return -1; | |
} | |
for(i=0; i<nSrcLength; i++) | |
{ | |
*pDst++ = tab[*pSrc >> 4]; // Êä³öµÍ4λ | |
*pDst++ = tab[*pSrc & 0x0f]; // Êä³ö¸ß4λ | |
pSrc++; | |
} | |
// ·µ»ØÄ¿±ê×Ö·û´®³¤¶È | |
return nSrcLength * 2; | |
} | |
//lower case | |
int bytes2string_lower(const unsigned char* pSrc, char* pDst, int nSrcLength) | |
{ | |
const char tab[]="0123456789abcdef"; // 0x0-0xfµÄ×Ö·û²éÕÒ±í | |
int i = 0; | |
//УÑé²ÎÊý | |
if(pSrc == NULL || pDst == NULL || nSrcLength < 0) | |
{ | |
return -1; | |
} | |
for(i=0; i<nSrcLength; i++) | |
{ | |
*pDst++ = tab[*pSrc >> 4]; // Êä³öµÍ4λ | |
*pDst++ = tab[*pSrc & 0x0f]; // Êä³ö¸ß4λ | |
pSrc++; | |
} | |
// ·µ»ØÄ¿±ê×Ö·û´®³¤¶È | |
return nSrcLength * 2; | |
} | |
char *lpa_base64_encode(const char*data, int data_len) | |
{ | |
//int data_len = strlen(data); | |
int prepare = 0; | |
int ret_len; | |
int temp = 0; | |
char *ret = NULL; | |
char *f = NULL; | |
int tmp = 0; | |
char changed[4]; | |
int i = 0; | |
const char base[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; | |
if(data == NULL) | |
{ | |
return NULL; | |
} | |
if(data_len == 0) | |
{ | |
return NULL; | |
} | |
ret_len = data_len / 3; | |
temp = data_len % 3; | |
if (temp > 0) | |
{ | |
ret_len += 1; | |
} | |
ret_len = ret_len*4 + 1; | |
ret = (char *)malloc(ret_len); | |
if (ret == NULL) | |
{ | |
printf("No enough memory.\n"); | |
return NULL; | |
} | |
memset(ret, 0, ret_len); | |
f = ret; | |
while (tmp < data_len) | |
{ | |
temp = 0; | |
prepare = 0; | |
memset(changed, '\0', 4); | |
while (temp < 3) | |
{ | |
//printf("tmp = %d\n", tmp); | |
if (tmp >= data_len) | |
{ | |
break; | |
} | |
prepare = ((prepare << 8) | (data[tmp] & 0xFF)); | |
tmp++; | |
temp++; | |
} | |
prepare = (prepare<<((3-temp)*8)); | |
//printf("before for : temp = %d, prepare = %d\n", temp, prepare); | |
for (i = 0; i < 4 ;i++ ) | |
{ | |
if (temp < i) | |
{ | |
changed[i] = 0x40; | |
} | |
else | |
{ | |
changed[i] = (prepare>>((3-i)*6)) & 0x3F; | |
} | |
*f = base[changed[i]]; | |
//printf("%.2X", changed[i]); | |
f++; | |
} | |
} | |
*f = '\0'; | |
return ret; | |
} | |
unsigned char *lpa_base64_decode(const unsigned char *src, int len, int *out_len) | |
{ | |
unsigned char dtable[256] = {0};//kw | |
unsigned char *out = NULL; | |
unsigned char *pos = NULL; | |
unsigned char in[4] = {0}; | |
unsigned char block[4] = {0}; | |
unsigned char tmp = 0; | |
int i = 0; | |
int count = 0; | |
int olen = 0; | |
memset(dtable, 0x80, 256); | |
for (i = 0; i < sizeof(base64_table) - 1; i++) | |
dtable[base64_table[i]] = (unsigned char) i; | |
dtable['='] = 0; | |
count = 0; | |
for (i = 0; i < len; i++) { | |
if (dtable[src[i]] != 0x80) | |
count++; | |
} | |
if (count == 0 || count % 4) | |
return NULL; | |
olen = count / 4 * 3; | |
pos = out = malloc(olen); | |
if (out == NULL) | |
return NULL; | |
memset(pos, 0, olen); | |
count = 0; | |
for (i = 0; i < len; i++) { | |
tmp = dtable[src[i]]; | |
if (tmp == 0x80) | |
continue; | |
in[count] = src[i]; | |
block[count] = tmp; | |
count++; | |
if (count == 4) { | |
*pos++ = (block[0] << 2) | (block[1] >> 4); | |
*pos++ = (block[1] << 4) | (block[2] >> 2); | |
*pos++ = (block[2] << 6) | block[3]; | |
count = 0; | |
} | |
} | |
if (pos > out) { | |
if (in[2] == '=') | |
pos -= 2; | |
else if (in[3] == '=') | |
pos--; | |
} | |
*out_len = pos - out; | |
return out; | |
} | |
//lpa code | |
//0 ok, -1 error, 9000 91XX 92XX and 61XX | |
int lpa_csim_resp_code(char *atres_apdu, int *second_len) | |
{ | |
int pdu_len = 0; | |
char sw1_s[3] = {0}; | |
char sw2_s[3] = {0}; | |
int sw1 = 0; | |
int sw2 = 0; | |
int res = -1; | |
pdu_len = strlen(atres_apdu);//kw 1 | |
if (pdu_len < 4) { | |
printf("lpa_csim_resp_code len err:%d\n", pdu_len); | |
return res; | |
} | |
strncpy(sw1_s, atres_apdu + pdu_len - 4, sizeof(sw1_s) - 1); | |
strncpy(sw2_s, atres_apdu + pdu_len - 2, sizeof(sw2_s) - 1); | |
errno = 0; | |
sw1 =strtol(sw1_s, NULL, 16); | |
if (errno == ERANGE)// kw ERRNO.NOT_CHECKED | |
{ | |
printf("strtol errno %d: %s\n", errno, strerror(errno)); | |
} | |
errno = 0; | |
sw2 =strtol(sw2_s, NULL, 16); | |
if (errno == ERANGE)// kw ERRNO.NOT_CHECKED | |
{ | |
printf("strtol errno %d: %s\n", errno, strerror(errno)); | |
} | |
if ((sw1 == 0x90 && sw2 == 0x00) || (sw1 == 0x91) || (sw1 == 0x92)) { | |
*second_len = 0; | |
res = 0; | |
} | |
else if(sw1 == 0x61) { | |
*second_len = sw2; | |
if (sw2 == 0x00) {//tianyu: bigger than 256, use 00c0000000 | |
*second_len = 0xFF; | |
} | |
res = 0; | |
} | |
return res; | |
} | |
//0 ok, -1 error, 9000 91XX 92XX | |
int lpa_csim_resp_normal(char *atres_apdu) | |
{ | |
int pdu_len = 0; | |
char sw1_s[3] = {0}; | |
char sw2_s[3] = {0}; | |
int sw1 = 0; | |
int sw2 = 0; | |
pdu_len = strlen(atres_apdu);//kw 1 | |
if (pdu_len < 4) { | |
printf("lpa_csim_resp_normal len err:%d\n", pdu_len); | |
return -1; | |
} | |
strncpy(sw1_s, atres_apdu + pdu_len - 4, sizeof(sw1_s) - 1); | |
strncpy(sw2_s, atres_apdu + pdu_len - 2, sizeof(sw2_s) - 1); | |
errno = 0; | |
sw1 =strtol(sw1_s, NULL, 16); | |
if (errno == ERANGE)// kw ERRNO.NOT_CHECKED | |
{ | |
printf("strtol errno %d: %s\n", errno, strerror(errno)); | |
} | |
errno = 0; | |
sw2 =strtol(sw2_s, NULL, 16); | |
if (errno == ERANGE)// kw ERRNO.NOT_CHECKED | |
{ | |
printf("strtol errno %d: %s\n", errno, strerror(errno)); | |
} | |
//normal processing: 9000 91XX 92XX | |
if ((sw1 == 0x90 && sw2 == 0x00) || (sw1 == 0x91) || (sw1 == 0x92)) { | |
return 0; | |
} | |
return -1; | |
} | |
//delete sw1 sw2 | |
char *lpa_get_apdu_from_atresp(char *atres_apdu) | |
{ | |
int pdu_len = 0; | |
char *apdu = NULL; | |
pdu_len = strlen(atres_apdu);//kw | |
if (pdu_len < 4 || pdu_len >= APDU_RESP_LEN) | |
return NULL; | |
apdu = malloc(APDU_RESP_LEN); | |
if (apdu == NULL) | |
return NULL; | |
memset(apdu, 0, APDU_RESP_LEN); | |
strncpy(apdu, atres_apdu, pdu_len - 4);//len = 4 -> "\0" | |
printf("get apdu: %s\n", apdu); | |
return apdu; | |
} | |
//´ÓcsimµÄapduÖнâ³öÖ¸¶¨µÄtagµÄvalue(hexstring) | |
//Èç¹ûÓжà×éͬÃûtag£¬Ö»Äܽâ³öµÚÒ»×é | |
char *lpa_tag_apdu_from_atresp(char *atres_apdu, unsigned int tag) | |
{ | |
int pdu_len = 0; | |
char *apdu = NULL; | |
unsigned char *pdu_byte = NULL; | |
int nt_byte_len = 0; | |
pdu_len = strlen(atres_apdu);//kw | |
if (pdu_len <= 0) { | |
printf("atres_apdu len err:%d\n", pdu_len); | |
return NULL; | |
} | |
pdu_byte = malloc(pdu_len/2 + 1); | |
if (pdu_byte == NULL) { | |
printf("atres_apdu malloc fail\n"); | |
return NULL; | |
} | |
memset(pdu_byte, 0, pdu_len/2 + 1); | |
nt_byte_len = string2bytes(atres_apdu, pdu_byte, pdu_len); | |
if (nt_byte_len < 2) { | |
free(pdu_byte); | |
printf("atres_apdu to byte err\n"); | |
return NULL; | |
} | |
apdu = lpa_tlv_get_val_by_tag(pdu_byte, nt_byte_len, tag); | |
free(pdu_byte); | |
return apdu; | |
} | |
//9812.... to 8921 | |
void lpa_trans_iccid(char *iccid, int len) | |
{ | |
char low = 0; | |
char high = 0; | |
int i = 0; | |
if (iccid == NULL || len != ICCID_LEN) { | |
printf("iccid check fail\n"); | |
return; | |
} | |
for(i = 0; i < len; i += 2) | |
{ | |
low = *(iccid); | |
high = *(iccid + 1); | |
*(iccid) = high; | |
*(iccid + 1) = low; | |
iccid = iccid + 2; | |
} | |
} | |