通过 HID OMNIKEY 5427 CK 向卡发送 APDU 命令

Posted

技术标签:

【中文标题】通过 HID OMNIKEY 5427 CK 向卡发送 APDU 命令【英文标题】:Send APDU command to card through HID OMNIKEY 5427 CK 【发布时间】:2017-06-19 04:54:48 【问题描述】:

我正在尝试通过 HID OMNIKEY 5427 CK 通过 APDUs 命令来操作 MIFARE 卡,即。 Ultralight C 卡,在 Windows 10 x64 OS 环境中使用 WinSCard.dll。 (我在 NXP NDA 下,可以完全访问他们的文件)

我这几天一直在网上找资料。除了 2 页的小册子外,似乎没有针对此模型发布的文档。

GetUID(FFCA000000)这样简单的命令就可以了,我可以取回实际的卡UID。

但是对于“使用卡进行身份验证”,来自 HID 5421 模型的参考文档说我应该从 OpenGenericSession (FFA0000703010001) 开始,我试过了,读者总是回答 6D00h(错误)

我尝试直接发送身份验证命令'1Ah + 00h'(FFA00005080100F30000641A0000)阅读器也总是回复错误代码。

我体验过 HID 5421 型号,它非常简单,不知道为什么这款 5427 与它的兄弟姐妹不同。

是的,我联系了 HID 支持。没运气。我无法从他们那里得到任何有用的信息。

如果有人有想法或有 5427 软件开发指南,请帮助。到现在我已经拉了将近一个星期的头发了。

【问题讨论】:

我可以共享一个工作代码来使用 HID 5321/6321 读卡器访问 Ultralight-C(使用通用会话)——但您的问题似乎是 HID 5427 读卡器(我没有访问权限)到)。通用会话的有趣之处在于它适用于 Windows,但不适用于 linux(即使使用官方的全键驱动程序)。可能值得尝试检查 5427 是否使用与 5421 相同的驱动程序......祝你好运! 我的目标平台是 Windows,所以我希望我可以使用通用会话方法。请分享代码,我想所有 HID 设备之间的通用会话协议是相同的,但我在网上找不到 HID 演示该功能的示例。对我来说奇怪的是这个特殊的型号 5427 没有任何在线发布的开发指南。 .. 非常感谢您的编辑和慷慨。 @vlp 您知道您可以通过网页界面配置 OK5427CK 吗?也许你会在那里找到一个缺失的设置。 网页界面?我想我想念那个功能。你知道如何访问它吗? 是的,OK5427CK 是一款复合 USB 设备(智能卡读卡器 + 以太网接口)。您需要为 OK5427CK 安装 OMNIKEY 驱动程序,默认的 windows 驱动程序将不起作用。然后,您将在设备管理器以及您的网络连接中看到一个额外的“网络接口”。您应该可以通过192.168.63.99 调用它的接口(参见第 2 章,链接:goo.gl/hjj7Ut)遗憾的是,Web 接口驱动程序仅适用于 Windows 7 和更早版本。 【参考方案1】:

以下是使用 Omnikey 5321/6321 通过 通用会话 与 Ultralight-C 通信的概念验证 Java 代码:

private static final byte AF = (byte)0xAF;

protected static final byte[] PREFIX = new byte[]  0x01, 0x00, (byte) 0xF3, 0x00, 0x00, 0x64 ;

protected final CardChannel channel;

protected void openGenericSession() throws CardException 
    System.out.println("OPEN GENERIC SESSION");
    transmitAssert9000(new CommandAPDU(0xFF, 0xA0, 0x00, 0x07, new byte[]  0x01, 0x00, 0x01));


protected byte[] transmitRaw(byte[] data) throws CardException 
    System.out.println(" => " + toHex(data));
    byte[] ret = transmitAssert9000(new CommandAPDU(0xFF, 0xA0, 0x00, 0x05, ArrayUtils.addAll(PREFIX, data), 256));
    if(ret.length<2) 
        throw new RuntimeException();
    
    if((ret[0]==0x00)&&(ret[1]==0x00)) 
        // Success
        ret = Arrays.copyOfRange(ret, 2, ret.length);
        System.out.println(" <= " + toHex(ret));
        return ret;
    
    if((ret[0]==0x08)&&(ret[1]==0x04)&&(ret.length==3)) 
        // ACK/NAK
        switch(ret[2]) 
            case 0x0A:
                System.out.println(" <= ACK");
                return ArrayUtils.EMPTY_BYTE_ARRAY;
            default:
                // Buyer beware: very simplified
                System.out.println(" <= NAK");
                throw new RuntimeException("NAK");
        
    
    ret = Arrays.copyOfRange(ret, 2, ret.length);
    System.out.println(" <= " + toHex(ret));
    return ret;


protected static byte[] assert9000(ResponseAPDU transmit) 
    if(transmit.getSW()!=0x9000) 
        throw new RuntimeException("Unexpected response code");
    
    return transmit.getData();


protected byte[] transmitAssert9000(CommandAPDU commandAPDU) throws CardException 
    return assert9000(transmit(commandAPDU));


protected ResponseAPDU transmit(CommandAPDU commandAPDU) throws CardException 
    System.out.println(" -> " + toHex(commandAPDU.getBytes()));
    ResponseAPDU responseAPDU = channel.transmit(commandAPDU);
    System.out.println(" <- " + toHex(responseAPDU.getBytes()));
    return responseAPDU;


public byte[] read(int offset) throws CardException 
    System.out.println("READ");
    return transmitRaw(new byte[] 0x30, (byte)offset);

注意 1:此代码使用 javax.smartcardio 和 Apache Commons Lang。

注2:我写这段代码已经有一段时间了,请验证我的想法......

注 3:Ultralight-C 验证码见companion answer。


使用 Ultralight-C 的 Omnikey 6321 的通用会话示例跟踪(单线箭头表示 通用会话 APDU,双线箭头表示 Ultralight-C 命令):

OPEN GENERIC SESSION
 -> FFA0000703010001
 <- 9000
AUTHENTICATE
 => 1A00
 -> FFA00005080100F30000641A0000
 <- 0000AF4BDA4E34B5D04A019000
 <= AF4BDA4E34B5D04A01
 => AF6F18402E0F0E5357D854833B149FBB56
 -> FFA00005170100F3000064AF6F18402E0F0E5357D854833B149FBB5600
 <- 000000F0F667CCF0E140419000
 <= 00F0F667CCF0E14041
READ
 => 3003
 -> FFA00005080100F3000064300300
 <- 0000000000000000000000000000000000009000
 <= 00000000000000000000000000000000
CLOSE GENERIC SESSION
 -> FFA0000703010002
 <- 9000

一些补充说明:

(AFAIK) 此方法适用于 Windows(使用 Omnikey 驱动程序)。它在 linux 下不起作用(即使使用 Omnikey 驱动程序)。

1234563本文档)。

祝你好运!

【讨论】:

非常感谢。代码启发了我很多。不幸的是,对于 5427,OpenGeneric 会话 APDU 仍然不行。总是将 6D00 返回给我。我将继续研究您提供的 PC/SC 版本 2.02 第 3 部分规范,看起来很有希望。 @EricF。 : 你有5427的解决方案吗?请分享一下

以上是关于通过 HID OMNIKEY 5427 CK 向卡发送 APDU 命令的主要内容,如果未能解决你的问题,请参考以下文章

如果您有 IClass 卡的 UID,则读取卡上的卡号

如何访问 Omnikey 3121 智能卡读卡器

json 我的OmniKey搜索https://github.com/marioestrada/safari-omnikey

HDU 5427 A problem of sorting 水题

将 javax.smartcardio 用于 MIFARE Classic 和 Omnikey 5021 CL

使用 Omnikey 5022 读取 PACS(原始韦根)数据