【问题标题】:Basic Smart Card testing in WindowsWindows 中的基本智能卡测试
【发布时间】:2015-07-23 15:45:16
【问题描述】:

我正在尝试简单地测试 Windows 中是否存在智能卡。目标是运行一个“守护程序”,它会在插入卡片时(并且在持续时间内)执行操作。

我对这种性质的事情的经验为零。我已经阅读了 SCardStatus 等的文档,但我不明白整个 API 是如何工作的,所以我有点迷茫。

对我最有帮助的是,如果有人有一个非常简单的完整程序示例,可以简单地测试卡的存在(最好是在 C++ 中,但我会尽我所能!)。我将不胜感激。除了存在之外,我不需要任何卡状态。谢谢!

【问题讨论】:

  • 背景:我们最近被要求使用我们的 CAC 登录,忘记移除卡已成为普遍现象。这样第二天就很难进楼了……

标签: c++ smartcard


【解决方案1】:

如果您在 Windows 上工作,则需要使用 WinSCard API,如果您使用 unix,则使用 PCSC。由于标准的原因,这两个 API 非常相似,但 WinSCard API 更大,提供了更多可用的功能。这两个 API 是用 C 语言实现的,但是您可以很容易地将它们封装在 C++ 中。我只是想指出你是否要将这两个 API 封装到 C++ 中以便在 Windows 和 unix 上使用它,看看智能卡协议的数值,这些在这些平台上是不同的。

基础知识:

您需要建立上下文(就像创建智能卡管理器一样)

SCardEstablishContext

它需要 4 个参数,但对于基本使用,您只需要 2 个,范围和指向上下文句柄的指针。

LPSCARDCONTEXT hSCardContext = NULL;
int ret = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &hSCardContext);
if (ret != ERROR_SUCCES) ... // handle error

智能卡分为不同的组。所以有一些函数可以与组一起工作,创建它等等。

获取读者列表(对于您实际上并不需要群组的基本应用程序)

SCardListReaders

它需要4个参数,上下文,指向组的指针,指向阅读器的指针和指向阅读器计数的指针

你可以这样用它

char *szGroups = NULL;
long readers = 0;
int res = SCardListReaders(hSCardContext, szGroups, NULL, &readers);
// handle errors

您首先要计算读者数量。现在您可以为实际的阅读器分配内存了。

szReaders = (char *) malloc(sizeof(char) * readers);
int res = SCardListReaders(hSCardContext, szGroups, szReaders , &readers);

现在您已连接阅读器列表。

您可以像这样连接到阅读器

LPSCARDHANDLE hSCard = NULL;
long activeProtocols = 0;
int ret = SCardConnect(hSCardContext, myReader, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_TX, &hSCard, &activeProtocols);
// .. handle errors

指定协议,共享模式,如果您正在处理敏感的东西需要保护操作系统不会与事务交互,则使用 SCARD_SHARE_EXCLUSIVE 共享模式。

再一次,如果你是为 windows 和 unix 包装(unix 没有 SCARD_PROTOCOL_TX 协议),但它是这两个 SCARD_PROTOCOL_T0 | 的表示。 SCARD_PROTOCOL_T1。

myReader 是已连接阅读器的名称。喜欢(LPCTSTR)"Dermalog LF10" 您可以从 SCardListReaders 函数中获取这些阅读器名称。

现在您已连接到一张卡。使用 SCARD_SHARE_EXCLUSIVE 共享时不要忘记释放智能卡上下文,因为它会死锁。 使用SCardDisconnect断开连接,它需要2个参数,SmartCard句柄和配置,对于基本应用SCARD_LEAVE_CARD配置应该是可以的。它指定你不想对卡做任何特殊的事情,你不想弹出或其他什么。

交易更复杂,因为您需要了解 SCard 标准以及不了解的内容。但我涵盖了基础知识。

请记住,此代码可能无法编译,您需要改进类型,对于 Windows,您需要将这些类型转换为 WinAPI 类型,如 LPCTSTR,它不会抱怨,而 unix 没有此类类型,因此您需要解决也有这些问题。

【讨论】:

    【解决方案2】:

    此示例代码假定读卡器在开始时已插入,它不处理不断变化的读卡器数量。 除此之外,它只是通过插入/未插入卡的状态向控制台发送垃圾邮件。 请不要在生产代码中按原样使用它,大多数错误检查都被省略了,并且采用了一些快捷方式来保持代码简短(ish)。

    #pragma comment(lib, "winscard.lib")
    #include <vector>
    
    bool test()
    {
    
        DWORD dwReaders;
        LPSTR szReaders = NULL;
        SCARDCONTEXT hContext;
        bool bRunning = true;
    
        std::vector<const char*> cards;
    
        LONG status = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &hContext);
        if( status != SCARD_S_SUCCESS ) {
            return false;
        }
        dwReaders = SCARD_AUTOALLOCATE;
        if( SCardListReadersA(hContext, NULL, (LPSTR)&szReaders, &dwReaders) == SCARD_S_SUCCESS ) {
            LPSTR reader = szReaders;
            while (reader != NULL && *reader != '\0') {
                std::cout << "Reader name: '" << reader << "'" << std::endl;
                cards.push_back( reader );
                reader += strlen(reader)+1;
            }
            LPSCARD_READERSTATEA lpState = new SCARD_READERSTATEA[cards.size()];
            for( size_t n = 0; n < cards.size(); ++n ) {
                memset( lpState + n, 0, sizeof(SCARD_READERSTATEA) );
                lpState[n].szReader = cards[n];
            }
    
            do {
                status = SCardGetStatusChangeA( hContext, 500, lpState, cards.size() );
                switch( status )
                {
                case SCARD_S_SUCCESS:
                case SCARD_E_TIMEOUT:
                    for( size_t n = 0; n < cards.size(); ++n ) {
                        if( lpState[n].dwEventState & SCARD_STATE_PRESENT) {
                            std::cout << "'" << lpState[n].szReader << "' present" << std::endl;
                        } else {
                            std::cout << "'" << lpState[n].szReader << "' not present" << std::endl;
                        }
                    }
                    break;
                default:
                    std::cout << "Other result: " << status << std::endl;
                    break;
                }
                Sleep( 1000 );  // do not spam too bad
            } while( bRunning );
            // only do this after being done with the strings, or handle the names another way!
            SCardFreeMemory( hContext, szReaders );
        }
        SCardReleaseContext( hContext );
        return true;
    }
    

    【讨论】:

      猜你喜欢
      • 2012-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-29
      • 2023-03-17
      • 1970-01-01
      • 2023-04-05
      • 1970-01-01
      相关资源
      最近更新 更多