[英]Sending and receiving data using same T=1 APDU
I'm trying to send an APDU that contains some command data, and then expect some data in response from the card. 我正在尝试发送包含一些命令数据的APDU,然后期望从卡中响应一些数据。 I'm using this example code by Ludovic Rousseau as a starting to point (modified code below).
我正在使用Ludovic Rousseau的这个示例代码作为起点(下面的修改代码)。
The APDU I'm sending is the following: 我发送的APDU如下:
0x80 0x02 0x00 0x00 0x08 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x08
Ie I've picked CLA 0x80
, INS 0x02
, not using P1 and P2, Lc and Le both 0x08
. 即我已经选择了CLA
0x80
,INS 0x02
,不使用P1和P2,Lc和Le都是0x08
。
The data buffer I get back only contains 0x90 0x00
. 我得到的数据缓冲区只包含
0x90 0x00
。
I've checked which protocol gets negotiated - that's T=1, as expected. 我已经检查了哪个协议得到了协商 - 这是T = 1,正如预期的那样。 If it were T=0, I would expect to get a
61XX
-series answer (see this related question ). 如果它是T = 0,我希望得到一个
61XX
系列的答案(参见这个相关的问题 )。
Every other APDU format works just fine (ie empty, only sending or only receiving data). 每个其他APDU格式都可以正常工作(即空,只发送或仅接收数据)。 Is there something I'm overlooking here?
有什么东西我在这里俯瞰吗?
// source: https://ludovicrousseau.blogspot.nl/2010/04/pcsc-sample-in-c.html
// This is based on code by Ludovic Rousseau, modified to match our example
#ifdef WIN32
#undef UNICODE
#endif
#include <stdio.h>
#include <stdlib.h>
#ifdef __APPLE__
#include <PCSC/winscard.h>
#include <PCSC/wintypes.h>
#else
#include <winscard.h>
#endif
#ifdef WIN32
static char *pcsc_stringify_error(LONG rv)
{
static char out[20];
sprintf_s(out, sizeof(out), "0x%08X", rv);
return out;
}
#endif
#define CHECK(f, rv) \
if (SCARD_S_SUCCESS != rv) \
{ \
printf(f ": %s\n", pcsc_stringify_error(rv)); \
return -1; \
}
int main(void)
{
LONG rv;
SCARDCONTEXT hContext;
LPTSTR mszReaders;
SCARDHANDLE hCard;
DWORD dwReaders, dwActiveProtocol, dwRecvLength;
SCARD_IO_REQUEST pioSendPci;
BYTE pbRecvBuffer[258];
BYTE selectapdu[] = { 0x00, 0xA4, 0x04, 0x00, 0x0A,
0x01, 0x02, 0x03, 0x04, 0x05,
0x48, 0x45, 0x4C, 0x4C, 0x4F };
BYTE echoapdu[] = { 0x80, 0x02, 0x00, 0x00, 0x08,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x08 };
unsigned int i;
rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
CHECK("SCardEstablishContext", rv)
#ifdef SCARD_AUTOALLOCATE
dwReaders = SCARD_AUTOALLOCATE;
rv = SCardListReaders(hContext, NULL, (LPTSTR)&mszReaders, &dwReaders);
CHECK("SCardListReaders", rv)
#else
rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);
CHECK("SCardListReaders", rv)
mszReaders = calloc(dwReaders, sizeof(char));
rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
CHECK("SCardListReaders", rv)
#endif
printf("reader name: %s\n", mszReaders);
rv = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
CHECK("SCardConnect", rv)
switch(dwActiveProtocol)
{
case SCARD_PROTOCOL_T0:
printf("T0\n");
pioSendPci = *SCARD_PCI_T0;
break;
case SCARD_PROTOCOL_T1:
printf("T1\n");
pioSendPci = *SCARD_PCI_T1;
break;
}
// selecting the application
dwRecvLength = sizeof(pbRecvBuffer);
rv = SCardTransmit(hCard, &pioSendPci, selectapdu, sizeof(selectapdu),
NULL, pbRecvBuffer, &dwRecvLength);
CHECK("SCardTransmit", rv)
printf("response (%d): ", dwRecvLength);
for(i=0; i<dwRecvLength; i++)
printf("%02X ", pbRecvBuffer[i]);
printf("\n");
// sending a non-empty APDU that expects a reply
dwRecvLength = sizeof(pbRecvBuffer);
printf("sent (%d): ", sizeof(echoapdu));
for(i=0; i<sizeof(echoapdu); i++)
printf("%02X ", echoapdu[i]);
printf("\n");
rv = SCardTransmit(hCard, &pioSendPci, echoapdu, sizeof(echoapdu),
NULL, pbRecvBuffer, &dwRecvLength);
CHECK("SCardTransmit", rv)
printf("response (%d): ", dwRecvLength);
for(i=0; i<dwRecvLength; i++)
printf("%02X ", pbRecvBuffer[i]);
printf("\n");
// disconnecting
rv = SCardDisconnect(hCard, SCARD_LEAVE_CARD);
CHECK("SCardDisconnect", rv)
#ifdef SCARD_AUTOALLOCATE
rv = SCardFreeMemory(hContext, mszReaders);
CHECK("SCardFreeMemory", rv)
#else
free(mszReaders);
#endif
rv = SCardReleaseContext(hContext);
CHECK("SCardReleaseContext", rv)
return 0;
}
This gives as output: 这给出了输出:
reader name: OMNIKEY AG CardMan 3121 00 00
T1
response (2): 90 00
sent (14): 80 02 00 00 08 01 02 03 04 05 06 07 08 08
response (2): 90 00
When I try to do the same thing in Python using pyscard
, everything works as expected, ie calling data, sw1, sw2 = connection.transmit(...)
with the same APDU bytes as input makes data
contain the expected data. 当我尝试使用
pyscard
在Python中做同样的事情时,一切都按预期工作,即调用data, sw1, sw2 = connection.transmit(...)
与输入相同的APDU字节使data
包含预期的数据。
This makes me believe that the relevant code on the card is fine (but also posted below for completeness). 这让我相信卡上的相关代码很好(但为了完整性也在下面发布)。
private void getEcho(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short numBytes = (short) (buffer[ISO7816.OFFSET_LC] & 0x00FF);
short bytesRead = apdu.setIncomingAndReceive();
short pos = 0;
while (pos < numBytes) {
Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, transientMemory, pos, bytesRead);
pos += bytesRead;
bytesRead = apdu.receiveBytes(ISO7816.OFFSET_CDATA);
}
apdu.setOutgoing();
apdu.setOutgoingLength(numBytes);
apdu.sendBytesLong(transientMemory, (short)0, bytesRead);
}
I'm not sure why you would receive the correct data through pyscard. 我不确定为什么你会通过pyscard收到正确的数据。 However, using
bytesRead
as the length in apdu.sendBytesLong()
is obviously a mistake: 但是,使用
bytesRead
作为apdu.sendBytesLong()
的长度显然是一个错误:
setIncomingAndReceive()
. setIncomingAndReceive()
检索, setIncomingAndReceive()
。 In that case, apdu.receiveBytes(ISO7816.OFFSET_CDATA)
will return zero and bytesRead
would be zero upon invoking sendBytesLong()
. apdu.receiveBytes(ISO7816.OFFSET_CDATA)
将返回零,并且在调用sendBytesLong()
时bytesRead
将为零。 bytesRead
would be set to the number (N) of bytes that were received with the last call of apdu.receiveBytes(ISO7816.OFFSET_CDATA)
. bytesRead
将被设置为最后一次调用apdu.receiveBytes(ISO7816.OFFSET_CDATA)
收到的字节数(N apdu.receiveBytes(ISO7816.OFFSET_CDATA)
。 sendBytesLong()
would return exactly this amount (N) of bytes from the beginning of the command data. sendBytesLong()
将从命令数据的开头准确返回此数量(N)的字节。 Consequently, the count should probably be numBytes
: 因此,计数应该是
numBytes
:
apdu.sendBytesLong(transientMemory, (short)0, numBytes);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.