安全 Pocket 商店






4.67/5 (14投票s)
了解如何在 Pocket PC 上使用 Microsoft 增强加密服务提供程序。
图 1 Secure Pocket Store
目录
引言 (版本 1.02)
在我为 The Code Project 撰写的第一篇文章中,我只是好奇如何开始用 C# 为 Pocket PC 编写一个真实的应用程序。现在我想知道我是否能够开发一个易于使用的、加密强度很强的数据存储,将我的数字化秘密保存在我的 Pocket PC 上。但是,您如何处理您的秘密,这些秘密值得隐藏起来不被窥探,例如密码、账户、身份、PIN 码等等?当然,您可以全部记住它们,或者购买像eWallet 这样的严肃获奖产品来保管它们。然而,对我来说,作为一个开发者,使用 Visual Studio .NET 创建这样的存储是很有挑战性的。因此,我邀请您和我一起学习如何在 .NET Compact Framework 应用程序中使用 Microsoft 增强加密服务提供程序。
基本的要求
首先,让我们定义一个敏感应用程序需要满足的主要加密要求,才能足够安全。它必须保证在丢失或被盗的情况下,能够防止密码分析和直接暴力破解攻击的高级别保护。
- 写入文件的秘密数据应使用工业标准强算法进行加密,使用至少 128 位的对称密钥。
- 每次都必须基于用户记住的密码短语创建对称密钥。
- 加密的数据文件不得包含预定义单词列表和可预测字符序列。
- 应用程序空闲几分钟后必须自动退出。
- 退出的应用程序不得在内存中留下秘密。
- 禁止将明文数据写入数据文件。
如果您对密码学完全不熟悉,请先阅读Neal Stephenson 的 Cryptonomicon。这本书不仅惊险刺激,还提供了关于黑客如何破解加密消息的真实线索。密码分析是破解密码系统的先进艺术,它是寻找实现中的弱点的过程。密码分析中的一种特殊方法基于未加密的明文可能包含的先验知识和假设。因此,仅仅使用带有已知预定义模式的加密有效 XML 文档的方法可能是一个坏主意,因为这种加密文件包含大量可预测的字符序列(XML 元素名称)。
本文描述的解决方案
加密入门
在考虑如何开始开发我的应用程序时,我首先希望我熟悉的 System.Security.Cryptography
类也能在 .NET Compact Framework 中得到支持。不幸的是,它们不行!因此,我被迫寻找是否能够找到使用 P/Invoke 的示例,以便能够访问 Microsoft Cryptographic Service Provider (MCSP) 函数。幸运的是,MSDN 上有一篇文章:Pocket PC Signature Application Sample,作者是 Ralph Arvesen。这篇文章包含一个自定义的 Crypto
类,它提供了我寻找的几乎所有东西。我对其进行了小的修改和扩展,以适应我的需求,如下所示:
- 原始的
Crypto
类使用的是 Microsoft Base Cryptographic Service Provider (MBCSP),它基于相对较弱(40 位)的密钥。我通过使用 Microsoft Enhanced Cryptographic Service Provider (MECSP) 扩展了该类,该提供程序支持更长的密钥(128 位)。 - 我还通过初始化向量 (IV) 功能扩展了
Crypto
类。这是通过声明两个额外的DllImport
来实现的,它们包含了CryptSetKeyParam()
和CryptGenRandom()
函数。 - 接下来,我通过重写的
Encrypt
和Decrypt
方法扩展了该类,这些方法也引用了初始化向量。稍后我将向您解释为什么 IV 很重要。
考虑到 MECSP 对称加密算法(DES、Triple DES、RC2、RC4)的可用性,我决定使用行业标准 RC2 分组加密算法,采用链式分组加密和 128 位密钥长度。这被认为比 RC4 等流加密算法更安全。DES 通常被认为不够安全。然而,Triple DES 也是一个不错的替代方案,提供与 RC2 类似的保护级别。该应用程序还将使用随机生成的 IV。
有关Microsoft Cryptographic Service Providers 的附加信息可以在 MSDN 上找到。如果您想了解更多关于密码学的普遍知识,我推荐Bruce Schneier 的经典著作。另一本专门为 .NET 用户准备的优秀书籍是 Wrox Press 出版的C# Data Security Handbook。我通过阅读这本书学到了很多,并且我可以诚实地鼓励您从初学者级别开始,轻松地在 .NET 中进行实际的密码学学习。
存储的数据结构
安全存储应该有一个明确定义的结构,用于保存独立的项目。在处理 .NET 时,DataSet
类提供了这样的结构。DataSet
易于使用,其内容易于持久化,底层数据源可以轻松连接到 ComboBox
等控件(我在本应用程序中使用了它,如图 1 所示)。因此,核心文档结构可以非常简单地保存,如图 2 所示。
<MyStore>
<Secrets>
<SecretName>First Item</SecretName>
<SecretData> RC2 encrypted; Base64 encoded </SecretData>
</Secrets>
<Secrets>
<SecretName>Second Item</SecretName>
<SecretData> RC2 encrypted; Base64 encoded </SecretData>
</Secrets>
<Secrets>
...
</Secrets>
</MyStore>
图 2 存储的基本数据结构
请注意,“MyStore
”是 DataSet
的名称,“Secrets
”元素指单个表名,而“SecretName
”和“SecretData
”元素指表的列。此外,请注意,“SecretData
”元素的值包含已加密的数据。加密内容根据 W3C XML 文本内容要求(字符数据)进行了 Base64 编码。
每个项目(SecretData
元素值)都基于其自己的唯一 128 位加密随机对称密钥进行加密,该密钥由 MECSP 使用初始登录密码(或密码短语)和特定项目名称(SecretName
元素值)创建。将这样的 XML 文档保存到文件已经足够安全,因为密码分析者将被迫破解与存在的秘密项目一样多的对称密钥。然而,加密整个包装器 XML 结构将提供额外的保护级别,原因如下:
- 每个项目名称(
SecretName
元素值)都可以随意选择,而不会暴露隐藏内容并提供先验知识。 - 每个项目的内容(
SecretData
元素值)将使用 128 位对称密钥进行两次加密。
但让我提醒您我在引言中解释过的顾虑。简单地加密 XML 文档会为密码分析者提供过多的先验知识。因此,每次应用程序启动一个空数据存储时,它都会提议随机生成的 XML 元素名称,打乱原始 XML 文档,如图 3 所示。因此,生成的每个新文档结构都不同,无法推测元素名称。
<xv56_df2a>
<kwfo7tg1a_>
<df2>First Item</df2>
<o7fg> RC2 encrypted; Base64 encoded </o7fg>
</kwfo7tg1a_>
<kwfo7tg1a_>
<df2>Second Item</df2>
<o7fg> RC2 encrypted; Base64 encoded </o7fg>
</kwfo7tg1a_>
<kwfo7tg1a_>
...
</kwfo7tg1a_>
</xv56_df2a>
图 3 存储的基本数据结构
图 3 中显示的 XML 文档结构更适合此类应用程序。对于 DataSet
,表名是“Secrets”还是“kwfo7tg1a_”或类似的随机字符串,都没有关系。
我们最后要解决的问题是,即使是带有打乱元素名称的 XML 文档,也总是以字节顺序标记或“<”字符开头,这也是一个不受欢迎的先验知识。这就是我之前提到的初始化向量 (IV) 的引入原因。
初始化向量
有时加密消息由于预定义头部(如电子邮件)而每次都以完全相同的序列开头。这种数据很容易受到攻击,因为密码分析可以利用已知的起始序列。初始化向量 (IV) 是对此类漏洞的有效保护。IV 默认设置为与分组密码的长度相同。使用 MECSP 提供的 RC2,分组大小默认设置为 64 位(8 字节),这也是 IV 的长度。IV 在每次写入时由 MECSP 生成,提供一个加密随机值。此值用于“打乱”文档的最初 8 个起始字节。IV 不应被视为第二个密钥,并且可以安全地与安全数据存储一起存储。对于不知道对称密钥的人来说,IV 是无用的。IV 在应用程序每次启动和解密现有数据存储时使用。
关于密码短语
我只想强调一点,如果依赖于密码分析者在每个字典中都能找到的易于猜测的密码,那么使用增强型对称算法、长密钥和初始化向量的全部努力都是徒劳的。使用此 Pocket PC 应用程序,您只需记住一个足够强的密码,但该密码必须绝对不可预测。
解决方案中的项目列表
该解决方案的结构与我在Pocket PC 货币转换器一文中解释的完全相同。因此,我将简要介绍。该解决方案包含三个独立的项目,按其确切的生成顺序排列,反映了依赖关系。
- SecurePocketStore - C# Mobile Smart Device 应用程序项目。
- InstallerService - C# 类库项目。
- Setup and Deployment 项目,打包安装程序包和 InstallerService 项目的主要输出。
SecurePocketStore 项目
该项目基于前面提到的扩展的 Crypto
类构建。幸运的是,这个 Crypto
类也可以在桌面应用程序中使用。然而,在为 Pocket PC 开发时,您必须声明“COMPACT_FRAMEWORK
”条件编译常量(图 4),否则 P/Invoke 将将调用重定向到桌面 Windows 库,如图 6 所示。
图 4 项目属性页
#if COMPACT_FRAMEWORK
const string CryptDll = "coredll.dll";
const string KernelDll = "coredll.dll";
#else
const string CryptDll = "advapi32.dll";
const string KernelDll = "kernel32.dll";
#endif
图 5 引用适当的库
我创建了一个名为 EnhancedCrypto
的 Crypto
类包装器,它提供 Secrets 区域(一个多行 TextBox
控件)的加密/解密和 Base64 编码/解码,并且还加密/解密 DataSet
并将其读写到文件中。
让我们仔细看看应用程序的结构,它被设计成同时处理纵向和横向模式,如图 6 所示。实现这一点的方法在我提到的文章中有详细解释。
应用程序的控制中心是核心的 ComboBox
控件以及包含您将要输入的秘密的多行 TextBox
控件。所有这些控件都放置在一个根 TabControl
的 TabPage
上。
打开的 ComboBox
控件显示项目名称列表,这些名称指向独立的秘密片段。每个项目(记录)由一个唯一的名称和一个秘密组成。特定秘密的明文大小默认限制为 32K。我不相信您会因为这个大小而受到限制。每次 TextBox
控件失去焦点时,该区域都会被加密/编码并保存在 DataSet
中。密钥对于每个项目都是唯一的,并且是基于组合的密码短语和项目名称字符串生成的。但是,您可以安全地通过单击“Alter”按钮来更改项目名称。如果您接受更改,将立即为秘密生成一个新密钥。
您可以通过直接在 ComboBox
的下拉菜单中选择一行,或者使用 ComboBox
下方的左右箭头按钮来导航 ComboBox
中显示的项目。正如您所见,您还可以导航到列表中的第一个或最后一个项目。此外,您还可以通过单击 Sort CheckBox
控件来对项目进行排序,这也可能会影响哪个项目被视为第一个或最后一个。
图 6 应用程序横向模式
“Save & Close”按钮不仅保存加密的包装器 XML 文档结构,还会退出应用程序。正如您可能已经意识到的,Pocket PC 应用程序往往会永远保留在内存中。强制它们退出的唯一方法是通过:设置 / 系统 / 内存 / 运行程序列表,然后选择应用程序并单击“停止”按钮。当然,这种行为对于此类应用程序来说是完全没有用的。想象一下丢失或被盗的后果。
为了防止滥用您的秘密,Secure Store 应用程序必须在 Pocket PC 设备空闲自动关闭之前自动退出。默认情况下,每个新设备上的“如果未使用则关闭设备”电池电源属性设置为 3 分钟。因此,应用程序的自动退出时间必须少于 3 分钟。请参见图 1 右侧图片的底部区域,它以 30 秒为步长显示剩余的空闲分钟数。如果您单击 TextBox
,更改 ComboBox
选定的项目;触摸任何其他控件,计时器计数器将每次重置为初始的 2:30 分钟。
您已被警告。如果您关闭您的物理 Pocket PC 设备,Secure Store 应用程序将不会退出,而是保持挂起状态。
应用程序生命周期
首次启动应用程序时,它将创建一个空的 DataSet
,其中包含三个初始记录,名为“First Item”、“Second Item”和“Third Item”(登录后更改这些项目名称是完全安全的)。您还需要输入并确认您的密码(或更好的密码短语),并确认或甚至故意更改随机生成的打乱的 XML 元素名称(参见图 1 的左侧图片)。密码短语必须至少七个字符长,但建议选择更长的。其余的 XML 元素名称(表列)源自输入的两个已确认的 XML 元素名称(下载并查看源代码了解更多详细信息)。
如果应用程序检测到现有的加密存储,它将要求您输入密码才能登录。请记住,您或任何使用此应用程序的人只有五次输入正确密码的机会。第五次尝试失败后,应用程序将自动销毁加密文件。但是,您仍然会在您用于同步 Pocket PC 的台式机或笔记本电脑上拥有该文件的副本。
还有一种更改密码的可能性,这会导致解密所有项目(使用旧密码)然后用新密码加密所有项目。这也是应用程序的一个已知弱点,因为它会在运行和活动期间保留密码短语。退出应用程序时,密码短语和最后显示的秘密将被覆盖成垃圾并清除。
结论
在本文中,您了解了如何在 Pocket PC 上构建加密强度很强的应用程序。下载源代码并查看类。当然,您可以自行承担风险使用该应用程序。我使用它已有几周了,似乎工作良好。我目前有一个包含约 4K 密文和约 10 个项目的存储。如果您有任何建议,或者发现我的代码有错误,请随时与我联系。
参考文章
- Ralph Arvesen; Pocket PC Signature Application Sample
- MSDN Library; Microsoft Cryptographic Service Providers
- Matthew MacDonald, Erik Johansson; C# Data Security Handbook, Wrox Press, ISBN 1-86100-810-5
- Bruce Schneier; Books website
- Stefan Repas; Currency Converter for the Pocket PC.