示例应用程序的实现方法
卡模块接口设计基本原理
文章的剩余部分将重点讨论栈顶:主机应用程序和 PC/SC 客户端 API。接着,我将讨论此编程模型的局限性及其发展过程。
使用 CLR 加密
更重要的是,如果仔细体会 后 PC 时代和 PC+ 时代,两者所指其实是一致的。都在描述一种发展现状:即移动设备和云存储的发展,使得不同设备上的软件和数据之间的差别越来越淡化。
第三种方法,我实现了一个可接受部分初始化结构的本机打包程序,设置 dwS**uctSize 字段,**调用 SCardUIDlgSelectCardW。**,我通过 P/Invoke 向托管代码提供了本机打包程序。您可能已经猜出来了,我选择了这种做法。我知道,出于灵活性的考虑,将本机打包程序封装为**的 DLL 以及添加额外 DLL 的管理开销以支持单个 API 的做法令人很难接受,但我已经获知卡模块例程也需要类似的解决方案。换言之,我发现提供一个**的本机 DLL 是不可避免的。我将在下一节介绍卡模块例程。
我将创建一些代表数字媒体许可证的示例 XML 数据。**,我将使用加密密钥对对数据进行加密。同样,必需的 XML 和与加密相关的功能已通过 CLR 提供。我将通过卡模块保存数据和签名。这需要新的本机打包程序和用于本机例程的 P/Invoke 接口。下一步,既然该程序是用于测试的,我将反向执行前面的步骤。这就是说,我将把刚刚写入卡的文件读取出来。最后,我将通过 CLR 加密例程对数据进行解密。
WinSCard API 打包程序
整个行业还要着手应对客户隐私保护的要求。消费者需要一种保护特权信息的方法,昌吉电大,大家往往看到了办学点。,例如,美国的在线银行业很快会要求使用严格的身份验证。在这个过程中,消费者将使用诸如 Windows CardSpace 的技术选择在各种在线事务中,披露哪些个人信息。例如,在在线银行事务过程中,我可能很机密地证明我的社会保险号 (SSN) 与我的身份是绑定在一起的,但我不可能与之共享我的信用卡号码。反之,我会授权将我的信用卡号码(而不是 SSN)透露给电子商务网站。
我的示例是一个 Windows 数字权限管理 (DRM) 应用程序,该程序使用智能卡来存储数字媒体许可证。数字许可证包括数字签名的、经过压缩的 XML Blob。通过在许可证生命周期中与智能卡的交互,主机应用程序在卡上执行一些简单的命令:创建存储许可证的文件、写入文件、读取文件和删除文件。每个命令都对应于一个不同的字节序列。例如,如果应用程序确定被智能卡识别为“02”的文件(很多智能卡的文件**非常简单)包含了许可证 Blob,那么可以对相关的命令/字节序列进行编码:“读取 02 文件的前 128 个字节。”每个命令都是通过 WinSCard 函数 SCardTransmit 发送到卡上的。PC/SC资料,稍后,我将转回到这个话题。
然而,智能卡的部署也带来了其特有的挑战。整个行业需要更好的产品来部署和管理复杂的身份验证技术。比尔·盖茨在 RSA 2006 大会上做的主题发言中,演示了 Microsoft Certificate Lifecycle Ma****r,该产品充分利用了我们这篇文章中讨论的 API。
Windows 智能卡编程基础
Windows 已支持个人计算机/智能卡 (PC/SC) 软件堆栈将近十年了(详细信息,请参见 )。PC/SC 功能通过 Windows 智能卡 (WinSCard) 客户端 API 提供给应用程序,该 API 在 winscard.dll 和 scarddlg.dll 中实现(在后者中实现程度较小)。客户端 API 允许主机应用程序通过智能卡资源管理器服务(也称作 SCardSvr)与智能卡间接进行通信。
图 1 中汇总了 PC/SC 组件堆栈。请注意,PC/SC 客户端代码是在应用程序进程中加载的。资源管理器是一种**服务,是**于客户端的。读卡器设备驱动程序是唯一在内核模式下运行的 PC/SC 堆栈组件。读卡器驱动程序被资源管理器独占加载,以防止应用程序忽略事务模型。这是 PC/SC 安全模型很重要的一个方面。最后,本文中讨论的 API 只供用户模式调用程序使用。遗憾的是,没有内核模式的资源管理器。
我已经概要介绍了要在应用程序中看到的行为,现在让我们将各种功能要求分类。以下三个组成部分是所有我想要的东西:用于 WinSCard API 的打包程序、用于卡模块 API 的打包程序以及现有的 CLR 加密例程。一旦实现了这些*作并理解了其中的道理,编写应用程序这件事本身是很容易的!让我们仔细了解各个组成部分。我建议您下载示例 C# 代码并认真学习,这些代码中加入了一些关于智能卡编程基础的注释,增加了趣味性。
图 1PC/SC 组件堆栈
既然我已经有了卡句柄,就可以通过 P/Invoke 调用 SCardStatus API 以获取 ATR 了。您可以在 GetSmartCard 中看到我调用了两次 SCardStatus:一次
本文讨论:
[DllImport( winscard.dll )]
ref IntP** ontext);
下面是盖茨在 1本文源代码下载地址:
本文使用了以下技术:
我对卡句柄做的第二件事情是用句柄查询用于所选智能卡的 ATR(重置应答)字符串的 PC/SC。ATR 的字节组成了一个因卡类型而异的标识符,该标识符简化了卡与智能卡读卡器设备驱动程序之间的底层协议协商。也可以使用卡 ATR,通过**注册表,在卡和对应的卡模块之间实现映射(还可以在卡与对应的 CSP 之间,尽管这些数据是由加密 API 提取的)。换言之,为了加载正确的卡模块,我必须首先知道要与之交换信息的卡的 ATR。
Fig**e3GetSmartCard Helper Routine
依赖关系和测试
任何 Windows 智能卡应用程序的基础都是 SCardEstablishContext。从 winscard.dll 输出的 PC/SC 例程建立了句柄,该句柄允许应用程序与智能卡资源管理器交互。其功能非常简单,对于这些简单的功能,无需实现额外的本机打包程序。P/Invoke 接口足以:
第二种方法,您可以使用一个或多个 CLR 编排原始字节(如 Marshal.SizeOf)来确定被编排的结构在运行时的大小。不幸的是,在我的测试中,该特殊例程得到了令人意外的结果,表明特定数据成员经编排后的大小是无法确定的。而且,除非此方法得到的大小与本机大小是完全一样的,否则,这不是一个好主意。
首先,应用程序要找到并绑定到一个插入的智能卡。如果未插入智能卡,程序将提示用户插入一个智能卡。实现这些*作需要用到 WinSCard API,因此这一部分的应用程序对 P/Invoke 和本机打包程序非常依赖。
示例应用程序运用的第二个 PC/SC 例程 SCardUIDlgSelectCardW 是目前为止最难在 代码中使用的例程。这有两个原因。第一个原因,此函数使用了单个 C 样式结构作为其参数。(请参见平* SDK 中 winscard.h 定义的 OPENCARDNAME_EXW。)该结构除了包括若*个其他字段外,还包括两个充当输入和输出的 Unicode 字符数组。要正确地排定这个结构是要费些周折的。需要说明的是,这个结构包含一个可选的嵌入式结构:OPENCARD_SEARCH_CRITERIAW。该结构也是在 winscard.h 中定义的。这个嵌套结构不比第一个结构简单。对于这个示例而言,我选择不采用依赖于第二个结构的 SCardUIDlgSelectCardW 的高级功能。
迄今为止,智能卡在 Windows 中的典型用途通常与身份验证相关。例如,它们可以代替**进行登录。这些智能卡身份验证方案是基于加密技术的。这就导致一直以来,在 Windows 中添加对新型智能卡的支持始终要求供应商部署一个名为 CSP(加密服务提供商)的插件,该插件部署了名为 Crypto API 1.0 的接口。不幸的是,人人都知道 CSP 的编写工作非常复杂。而且,由于 CSP 接口是专用于低级别加密*作的,因此不能提供现代智能卡的各种丰富的新功能。这些功能包括增加的数据存储容量、高带宽 I/O、卡载小程序以及新的加密算法。由于缺少可实现这些功能的应用程序级别的编程模型,阻碍了硬件供应商生产出有别于人的商品,也阻碍着编程人员为各种硬件编写程序。
目录
CardReadFile(
// Size of the file contents如果您觉得新的 API 比旧方法简单很多,我完全同意。但别着急,还有一些工作要做!
由于智能卡是一种共享资源,在任何给定时间都可能有多个应用程序试图与该卡进行通信,因此要使用资源管理器模型。与该卡的通信必须是串行的。因此,资源管理器强制采用简化的、类似于数据库的锁定模型。在 PC/SC 中,持有给定智能卡读卡器(也称为接口设备或 IFD)的锁,就等于掌握了事务。然而,本文中“事务”这个术语可能会引起误解。例如,没有回滚或取消提交的事情发生,PC/SC 不能自动撤销应用程序在事务中作出的更改。
采用 SCardUIDlgSelectCardW 所面临的第二个挑战是,必须将 OPENCARDNAME_EXW 第一个数据成员初始化,使之与结构大小相同(以字节为单位)。我尝试了三种方法,试图将该字段初始化为正确的值。第一种方法,我试图对其进行硬编码 — 这就是说,确定该结构的大小(例如,通过调试程序或采用本机代码的简单测试应用程序),始终在托管代码中将该字段初始化为该值。使用易于移植的代码是很不错的,但是,在 64 位的环境下,该结构的大小会有所不同。
WinSCard API 打包程序
相反,如果使用新的 API,就可以通过调用单个函数来代替整个块:
s)在 2010 年和现任 CEO 蒂姆 库克(Tim Cook)在今年早些时候所强调的平板电脑与传统 PC 的不同,随着 iPad 的推出,苹果宣布 后 PC 时代的到来。static Int32 GetSmartCard(
}
我使用返回的卡句柄在 GetSmartCard 中做的第一件事情是调用 SCardBeginTransaction。这一*作授予了对智能卡的独占访问权限,防止其他应用程序(甚至该进程中的其他卡句柄)与该卡交互。如果 GetSmartCard 例程成功返回,事务仍然是保留的,我将使卡保持在锁定状态,直到调用托管的加密 API 例程为止。在那个时间点释放锁的原因很深奥,我将稍后作出解释。
示例智能卡应用程序的实现方法
在 SCardEstablishContext、SCardBeginTransaction 以及其他 WinSCard 函数的平* SDK 文档中可找到对 PC/SC 的其他说明。主机应用程序使用这些例程建立到资源管理器的管道,获得智能卡读卡器的独占锁,向卡发送一系列命令,**释放锁。
为了通过卡模块 API 与智能卡直接进行交互,我要做的第一件事就是为适当的卡获取 PC/SC 句柄。(请注意,此处引述的所有本机例程在 Platform SDK 中都有记录,因此我不会在此为用到的各个公共例程提供详细的使用方法。)为了绑定到来自托管应用程序的智能卡,我需要介绍几个本机 API。
Microsoft 已经认识到智能卡在其平*的安全战略中所扮演的重要角色。**人员需要了解可识别智能卡的应用程序的工作原理,以及 Windows *作**使用了何种方法,使生活变得更加轻松。
到现在为止,我已经描述了 PC/SC 软件堆栈和卡模块 API 的一些基本情况。我已经做好解决 DRM 应用程序示例代码的准备。由于我描述的智能卡相关接口都不向 Microsoft Framework 代码开放,如果我能将卡模块 API 的功能与 的方便之处结合起来,是不是很酷?
尽管在**战略和用户界面上有所不同,但理念基本一致。微软强调从 PC 到 Xbox,再到手机过程中的创新电大教学辅导,而苹果则强调从 iPhone 和 iPad 等移动设备回归到 Mac 方面的创新。
编写实现智能卡功能的托管打包程序
新的卡模块 API 通过提供与常见文件**类似的接口,处理卡不兼容的问题,并使用其他一些例程满足前面提到过的与加密有关的身份验证要求。例如,如果应用程序采用的是针对各种卡进行“读取 02 文件的前 128 个字节”命令编码的旧模式,则伪代码可能与图 2 类似。
处理 CardAcquireContext
随后,特纳引入了微软的 PC+ 时代。事实上,乔布斯早在 2007 年讨论 iPhone 和 iPod 时就公开使用过 后 PC 时代一词。而 PC+ 时代可能更久远,早在 1999 年比尔 盖茨(Bill Gates)就使用过,而且在理解上也与今天特纳所说的基本一致。
该应用程序做的第一件事情是调用 加密 API,找到合适的密钥对。但是,我将在介绍完该应用程序进行的底层智能卡 API 调用之后再讨论这部分问题,以阐明我对整体体系架构的看法。
首先,我将概述示例应用程序需要做什么。**详细讨论打包程序和 P/Invoke 接口。
Fig**e2Pseudocode for mand Handling
我发现可采用最常规的解决方案来提供代码打包程序,该程序可通过 P/Invoke(一种机制,用于调用来自托管代码的本机 DLL 输出)实现所需的 WinSCard 和卡模块例程。**,我可以用托管代码演示整个应用程序。我发现如果编写其他打包程序代码来简化任务,可以使事情简单一点。以前,如果不熟悉本机 API 的知识,实现托管接口是非常困难的。
Windows 智能卡编程
智能卡的发展
智能卡的发展
智能卡(简单地说,就是嵌入了微型芯片的信用卡)的概念已经提出将近 30 年了。但现在安全工作的重点是让公司和**等机构重新审视一些早已有之的理念。
示例应用程序的实现方法
这篇文章基于 Windows Vista 的预发布版而撰写。其中包含的信息可能会有所变动。
[DllImport( mgsc.dllCharSet=CharSet.Unicode)]
PCSCOpenCardNameWEx wex);让该 API 正常工作后,其他工作就显得非常简单了!
智能卡事务管理
值得高兴的是,由于采用了被称作“卡模块 API”的新插件模型,Windows Vista 中的情况已大大改善。新 API 最大的优点是允许可识别智能卡的应用程序不知道卡的具体类型。让我们看一个示例。
Windows 智能卡编程
事务管理
在示例代码中,MgSc.dll(托管智能卡的缩写)输出本机打包程序例程。打包程序例程的代码(包括 MgScSCardUIDlgSelectCardW)存储在 MgSc.cpp 中。该 DLL 中用于所有本机打包程序的 P/Invoke 类也称作 MgSc;它包含与以下内容类似的 P/Invoke 占位程序:
if (cardType == A) {
}
要普及可识别智能卡的应用程序,需要注意的一个问题是各个供应商使用的命令编码是不同的。就算已经有了一些标准化编码(如 ISO 7816),并且针对基本*作(如读取文件)的 ISO 编码可能的确适用于多种卡,但通常**人员不能指望这些编码。因此,必须对本示例中的 DRM 应用程序进行修改,以支持各种新的智能卡类型。根据我的经验,构建这些智能卡命令字节序列的应用程序代码非常杂乱,很难维护。
GetSmartCard 帮助器例程
Windows Vista, CC#
**,我将打开卡上的加密密钥对的句柄。如何没有合适的密钥对,我将新建一个。幸运的是,所需的与加密相关的功能已经通过 CLR 提供了,因此一切都很简单。对于应用程序的加密部分,有一个潜在的障碍:必须安装新版本的基本智能卡加密服务提供程序 (Base Smart Card Crypto Service Provider),这是与基于卡模块的卡交换数据最可*的方法。
卡模块 API 打包程序
对于身份验证**的脆弱连接(即**)来说,智能卡是一个很吸引人的替代方法。整个行业非常需要能够替代**的技术。借助嵌入式的加密处理器,智能卡提供了非常安全且易于使用的身份验证机制。
图 3 显示了摘录的示例代码中的 GetSmartCard 帮助器例程。请注意,如果 MgScSCardUIDlgSelectCardW 是成功的,则意味着 PCSCOpenCardNameWEx 参数的 cardHandle 成员被初始化并对应于一个已插入的智能卡。换言之,我们已经可以使用这张卡了。
GetSmartCard 帮助器例程