SCardTransmit 返回 87 (0x57),不知道出了什么问题。 SCardTransmit 与 SELECT 和 READ RECORD 配合使用

问题描述 投票:0回答:1

尝试使用 ACR39U 读卡器发送 GPO 失败,错误代码为 87 (0x57)、INVALID_PARAMETERS,适用于其他读卡器。它还可以与 SELECT 和 READ RECORD 一起使用。

这是我的 APDU 日志。

00 A4 04 00 0E 31 50 41 59 2E 53 59 53 2E 44 44 46 30 31

00 B2 01 0C 32

00 A4 04 00 08 A0 00 00 03 33 01 01 01

80 A8 00 00 0A 83 08 00 00 00 00 10 00 02 12 00

对于其他读卡器,它会返回正确的响应,但对于 ACR39U,它总是返回 87。这是隔离此问题的源代码。它是用 C#、.NET8 编写的。我在 Visual Studio 中使用任何 CPU。 Windows 11。卡是银联卡。

using System;
using System.Runtime.InteropServices;

public class SmartCardCommunication
{
    [DllImport("winscard.dll")]
    private static extern int SCardEstablishContext(uint dwScope, IntPtr pvReserved1, IntPtr pvReserved2, ref IntPtr phContext);

    [DllImport("winscard.dll")]
    private static extern int SCardReleaseContext(IntPtr hContext);

    [DllImport("winscard.dll")]
    private static extern int SCardListReaders(IntPtr hContext, string mszGroups, byte[] mszReaders, ref int pcchReaders);

    [DllImport("winscard.dll")]
    private static extern int SCardConnect(IntPtr hContext, string szReader, uint dwShareMode, uint dwPreferredProtocols, ref IntPtr phCard, ref uint pdwActiveProtocol);

    [DllImport("winscard.dll")]
    private static extern int SCardDisconnect(IntPtr hCard, int dwDisposition);

    [DllImport("winscard.dll")]
    private static extern int SCardTransmit(IntPtr hCard, ref SCARD_IO_REQUEST pioSendPci, byte[] pbSendBuffer, int cbSendLength, ref SCARD_IO_REQUEST pioRecvPci, byte[] pbRecvBuffer, ref int pcbRecvLength);

    private const uint SCARD_SCOPE_USER = 0;
    private const uint SCARD_SHARE_SHARED = 2;
    private const uint SCARD_PROTOCOL_T0 = 1;
    private const uint SCARD_PROTOCOL_T1 = 2;

    [StructLayout(LayoutKind.Sequential)]
    private struct SCARD_IO_REQUEST
    {
        public uint dwProtocol;
        public uint cbPciLength;
    }

    public static void Main()
    {
        IntPtr hContext = IntPtr.Zero;
        IntPtr hCard = IntPtr.Zero;
        uint activeProtocol = 0;

        try
        {
            int result = SCardEstablishContext(SCARD_SCOPE_USER, IntPtr.Zero, IntPtr.Zero, ref hContext);
            if (result != 0) throw new Exception("Failed to establish context.");

            int readerSize = 0;
            result = SCardListReaders(hContext, null, null, ref readerSize);
            if (result != 0) throw new Exception("Failed to list readers.");

            byte[] readers = new byte[readerSize];
            result = SCardListReaders(hContext, null, readers, ref readerSize);
            if (result != 0) throw new Exception("Failed to list readers.");

            string readerName = System.Text.Encoding.ASCII.GetString(readers).Split('\0')[0];

            result = SCardConnect(hContext, readerName, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, ref hCard, ref activeProtocol);
            if (result != 0) throw new Exception("Failed to connect to the card.");

            apdu(hCard, activeProtocol, "00 A4 04 00 0E 31 50 41 59 2E 53 59 53 2E 44 44 46 30 31 ");
            apdu(hCard, activeProtocol, "00 B2 01 0C 32 ");
            apdu(hCard, activeProtocol, "00 A4 04 00 08 A0 00 00 03 33 01 01 01 ");
            apdu(hCard, activeProtocol, "80 A8 00 00 0A 83 08 00 00 00 00 10 00 02 12 00 ");
        }
        finally
        {
            // Clean up
            if (hCard != IntPtr.Zero) SCardDisconnect(hCard, 0);
            if (hContext != IntPtr.Zero) SCardReleaseContext(hContext);
        }
    }

    static void apdu(IntPtr hCard, uint activeProtocol, string hex)
    {
        hex = hex.Replace(" ", "");
        byte[] apduCommand = StringToByteArrayFastest(hex); // Example: SELECT command
        byte[] recvBuffer = new byte[256];
        int recvLength = recvBuffer.Length;

        SCARD_IO_REQUEST ioRequest = new SCARD_IO_REQUEST { dwProtocol = activeProtocol, cbPciLength = (uint)Marshal.SizeOf(typeof(SCARD_IO_REQUEST)) };
        SCARD_IO_REQUEST ioRequest2 = new SCARD_IO_REQUEST { dwProtocol = activeProtocol, cbPciLength = (uint)Marshal.SizeOf(typeof(SCARD_IO_REQUEST)) };

        int result = SCardTransmit(hCard, ref ioRequest, apduCommand, apduCommand.Length, ref ioRequest2, recvBuffer, ref recvLength);
        if (result != 0) throw new Exception("Failed to transmit APDU command.");

        byte[] response = new byte[recvLength];
        Array.Copy(recvBuffer, response, recvLength);
        Console.WriteLine("Response: " + BitConverter.ToString(response));
    }

    public static byte[] StringToByteArrayFastest(string hex)
    {
        if (hex.Length % 2 == 1)
            throw new Exception("The binary key cannot have an odd number of digits");

        byte[] arr = new byte[hex.Length >> 1];

        for (int i = 0; i < hex.Length >> 1; ++i)
        {
            arr[i] = (byte)((GetHexVal(hex[i << 1]) << 4) + (GetHexVal(hex[(i << 1) + 1])));
        }

        return arr;
    }

    public static int GetHexVal(char hex)
    {
        int val = (int)hex;
        return val - (val < 58 ? 48 : (val < 97 ? 55 : 87));
    }
}

这可能是什么原因造成的?

c# smartcard apdu smartcard-reader emv
1个回答
0
投票

您似乎正在使用

T=0
协议(在
SCARD_PROTOCOL_T0
调用中给出
SCardConnect
)。

GET PROCESSING OPTIONS
是“情况 4”命令(详细信息请参阅 ISO 7816),需要根据
T=0
逻辑进行传输(请参阅此处)。

您的沟通应如下所示:

>> 80 A8 00 00 0A 83 08 00 00 00 00 10 00 02 12 (GET PROCESSING OPTIONS)
<< 61 XX (command successful, XX response data available)
>> 00 C0 00 00 XX (GET RESPONSE)
<< [response data] 90 00

您可能还会发现 EMV 第 3 册中的“9.3.1 通过 T=0 传输 APDU”一章很有趣。

© www.soinside.com 2019 - 2024. All rights reserved.