本文概述了 .NET 支持的加密方法和做法,包括 ClickOnce 清单。
加密简介
Internet 等公用网络不提供实体之间的安全通信手段。 通过此类网络的通信很容易被未经授权的第三方读取或修改。 加密有助于防止数据被查看,提供检测数据是否已修改的方法,并帮助通过其他不安全通道提供安全通信方式。 例如,可以使用加密算法加密数据,以加密状态传输,以后由预期方解密。 如果第三方截获加密数据,则很难解码。
在 .NET 中,命名空间中的 System.Security.Cryptography 类为你管理许多加密的详细信息。 有些是操作系统实现的包装器,而另一些则是纯托管实现的包装器。 你不需要是加密方面的专家才能使用这些类。 在创建其中一个加密算法类的新实例时,会自动生成密钥以方便使用,并且默认属性尽可能安全。
加密基元
在使用加密的典型情况下,两方(Alice 和 Bob)通过非安全通道进行通信。 Alice 和 Bob 希望确保他们的沟通让任何可能在倾听的人都无法理解。 此外,由于 Alice 和 Bob 位于远程位置,Alice 必须确保她在传输过程中从未被任何人修改从 Bob 接收的信息。 此外,她必须确保信息确实源自 Bob,而不是来自模拟 Bob 的人。
加密用于实现以下目标:
机密性:帮助保护用户的标识或数据不被读取。
数据完整性:帮助保护数据不被更改。
身份验证:确保数据源自特定方。
不可否认性:防止特定方否认其发送过消息。
为了实现这些目标,可以使用称为加密基元的算法和做法的组合来创建加密方案。 下表列出了加密基元及其用法。
加密基元 | 使用 |
---|---|
密钥加密(对称加密) | 对数据执行转换,防止第三方读取数据。 这种类型的加密使用单个共享的机密密钥来加密和解密数据。 |
公钥加密(非对称加密) | 对数据执行转换,防止第三方读取数据。 这种类型的加密使用公钥/私钥对来加密和解密数据。 |
加密签名 | 通过创建该方唯一的数字签名,帮助验证数据是否源自特定方。 此过程还使用哈希函数。 |
加密哈希 | 将数据从任何长度映射到固定长度字节序列。 哈希在统计上是唯一的;不同的双字节序列不会哈希到相同的值。 |
私钥加密
机密密钥加密算法使用单个密钥来加密和解密数据。 你必须保护密钥免受未经授权的代理的访问,因为拥有该密钥的任何一方都可以使用它来解密数据或加密自己的数据,声称它源自你。
密钥加密也称为对称加密,因为同一密钥用于加密和解密。 机密密钥加密算法非常快(与公钥算法相比),非常适合对大型数据流执行加密转换。 RSA 等非对称加密算法在数学上受限制,因为它们可以加密的数据量。 对称加密算法通常没有这些问题。
一种称为块密码的机密密钥算法用于一次加密一个数据块。 数据加密标准(DES)、TripleDES 和高级加密标准(AES)等块加密将 输入块 n 字节转换为加密字节的输出块。 如果要加密或解密一系列字节,必须按块进行处理。 由于 n 为小型(DES 和 TripleDES 为 8 个字节;16 个字节[默认值]、24 个字节或 AES 的 32 个字节),因此必须一次加密一个 块以上的数据 值。 小于 n 的数据值必须扩展为 n 才能进行处理。
块密码的一种简单形式称为电子编解码器(ECB)模式。 ECB 模式不被视为安全模式,因为它不使用初始化向量初始化第一个纯文本块。 对于给定的密钥 k,不使用初始化向量的简单块密码会将相同的纯文本输入块加密为同一个密码文本输出块。 因此,如果在输入纯文本流中有重复块,则输出密码文本流中将有重复块。 这些重复的输出块警告未经授权的用户所使用的弱加密算法及其可能的攻击模式。 因此,ECB密码模式很容易被分析,从而最终导致密钥曝光。
基类库中提供的块密码类使用名为密码块链(CBC)的默认链接模式,但如果需要,可以更改此默认值。
CBC 密码通过使用初始化向量(IV)加密第一个纯文本块来克服与 ECB 密码相关的问题。 每个后续的纯文本块在加密之前,都会与前一个密码文本块进行按位排他 OR(XOR
)操作。 因此,每个密码文本块都依赖于所有以前的块。 使用此系统时,可能无法将未经授权的用户已知的常见消息标头用于反向工程密钥。
一种泄露以 CBC 密码加密的数据的方式是对每个可能的密钥执行详尽搜索。 根据用于执行加密的密钥的大小,这种搜索非常耗时,甚至使用最快的计算机,因此是不可行的。 较大的密钥更难以破解。 尽管加密从理论上讲,攻击者无法检索加密的数据,但它确实增加了执行此作的成本。 如果执行详尽搜索需要三个月时间才能检索仅在几天内有意义的数据,则详尽的搜索方法是不切实际的。
密钥加密的缺点是,它假定双方已就密钥和 IV 达成一致,并传达了其值。 IV 不被视为机密,可以与消息一起以明文形式传输。 但是,密钥必须保密给未经授权的用户。 由于这些问题,机密密钥加密通常与公钥加密一起使用,以私下传达密钥和 IV 的值。
假设 Alice 和 Bob 是想要通过非安全通道进行通信的两方,则他们可能会使用密钥加密,如下所示:Alice 和 Bob 同意将一种特定算法(例如 AES)与特定密钥和 IV 配合使用。 Alice 撰写邮件并创建一个网络流(可能是命名管道或网络电子邮件),用于发送邮件。 接下来,她使用密钥和 IV 加密文本,并通过 Intranet 将加密的消息和 IV 发送到 Bob。 Bob 接收到加密的文本后,使用 IV 和之前约定的密钥来解密。 如果截获传输,侦听器无法恢复原始消息,因为它们不知道密钥。 在此方案中,只有密钥必须保持机密。 在实际方案中,Alice 或 Bob 会生成一个密钥,并使用公钥(非对称)加密将机密(对称)密钥传输到另一方。 有关公钥加密的详细信息,请参阅下一部分。
.NET 提供以下实现密钥加密算法的类:
HMACSHA256 HMACSHA384和 HMACSHA512 。 (这些算法在技术上是机密密钥算法,因为它们表示使用加密哈希函数与密钥组合计算的消息身份验证代码。请参阅本文后面的 哈希值。
公钥加密
公钥加密使用一个必须对未经授权的用户保密的私钥,以及一个可以向任何人公开的公钥。 公钥和私钥在数学上是链接的;使用公钥加密的数据只能使用私钥解密,使用私钥签名的数据只能使用公钥进行验证。 公钥可供任何人使用;它用于加密要发送到私钥的守护者的数据。 公钥加密算法也称为非对称算法,因为需要一个密钥来加密数据,另一个密钥需要解密数据。 基本加密规则禁止重复使用密钥,并且这两个密钥对于每个通信会话都应是唯一的。 但是,在实践中,非对称密钥通常长期存在。
两方(Alice 和 Bob)可以使用公钥加密,如下所示:首先,Alice 会生成公钥/私钥对。 如果 Bob 想向 Alice 发送加密消息,他要求她提供她的公钥。 Alice 通过非安全网络发送 Bob 她的公钥,Bob 使用此密钥来加密消息。 Bob 将加密的消息发送到 Alice,她使用私钥对其进行解密。 如果 Bob 通过非安全通道(如公共网络)收到 Alice 的密钥,Bob 将开放给中间人攻击。 因此,Bob 必须与 Alice 验证他是否有正确的公钥副本。
在 Alice 公钥的传输过程中,未经授权的代理可能会截获密钥。 此外,同一代理可能会截获 Bob 的加密消息。 但是,代理无法使用公钥解密消息。 消息只能使用 Alice 的私钥解密,该私钥尚未传输。 Alice 不使用她的私钥加密给 Bob 的答复消息,因为具有公钥的任何人都可以解密该消息。 如果 Alice 想要将消息发回 Bob,她要求 Bob 提供他的公钥,并使用该公钥加密她的消息。 然后,Bob 使用关联的私钥解密消息。
在此方案中,Alice 和 Bob 使用公钥(非对称)加密来传输机密(对称)密钥,并对其会话的其余部分使用密钥加密。
以下列表提供公钥和密钥加密算法之间的比较:
公钥加密算法使用固定缓冲区大小,而密钥加密算法则使用可变长度缓冲区。
公钥算法不能用于将数据链接到机密密钥算法可以采用的流中,因为只有少量的数据可以加密。 因此,非对称操作不使用与对称操作相同的流处理模型。
公钥加密的密钥空间(密钥的可能值范围)比密钥加密大得多。 因此,公钥加密不太可能受到尝试每个可能密钥的详尽攻击。
公钥很容易分发,因为它们不必受到保护,前提是存在验证发件人身份的某种方式。
某些公钥算法(例如 RSA 和 DSA,但不能 Diffie-Hellman)可用于创建数字签名来验证数据发送方的标识。
与密钥算法相比,公钥算法速度非常慢,不设计用于加密大量数据。 公钥算法仅适用于传输非常少量的数据。 通常情况下,公钥加密用于加密密钥算法要使用的密钥和 IV。 传输密钥和 IV 后,密钥加密将用于会话的其余部分。
.NET 提供实现公钥算法的以下类:
RSA 允许加密和签名,但 DSA 只能用于签名。 DSA 不如 RSA 那么安全,我们建议使用 RSA。 Diffie-Hellman 只能用于密钥生成。 一般来说,公钥算法的使用比私钥算法更有限。
数字签名
公钥算法还可用于形成数字签名。 数字签名对发件人的身份进行身份验证(如果你信任发件人的公钥),并帮助保护数据的完整性。 使用 Alice 生成的公钥,Alice 数据接收者可以通过将数字签名与 Alice 的数据和 Alice 的公钥进行比较来验证 Alice 是否发送了该密钥。
若要使用公钥加密对消息进行数字签名,Alice 首先向消息应用哈希算法来创建消息摘要。 消息摘要是数据的紧凑唯一表示形式。 然后 Alice 使用私钥加密消息摘要,以创建其个人签名。 收到消息和签名后,Bob 使用 Alice 的公钥解密签名,以恢复消息摘要,并使用 Alice 使用的相同哈希算法对消息进行哈希处理。 如果 Bob 计算的消息摘要与从 Alice 接收的消息摘要完全匹配,Bob 将确保消息来自私钥的拥有者,并且数据尚未修改。 如果 Bob 相信 Alice 是私钥的拥有者,他知道消息来自 Alice。
注释
任何人都可以验证签名,因为发件人的公钥是常见的知识,通常包含在数字签名格式中。 此方法不保留消息的保密性;对于消息为机密,还必须对其进行加密。
.NET 提供实现数字签名算法的以下类:
哈希值
哈希算法将任意长度的二进制值映射到固定长度的较小二进制值,称为哈希值。 哈希值是数据片段的数字表示形式。 如果对纯文本段落进行哈希处理并更改段落的一个字母,则后续哈希将生成不同的值。 如果哈希具有强加密性能,其值将显著改变。 例如,如果更改了消息的单个位,则强哈希函数可能会生成 50% 不同的输出。 许多输入值可能会哈希到相同的输出值。 但是,从计算上讲,几乎不可能找到两个不同的输入,使其哈希到相同的值。
两方(Alice 和 Bob)可以使用哈希函数来确保消息完整性。 他们会选择哈希算法来为其消息签名。 Alice 会编写一条消息,然后使用所选算法创建该消息的哈希。 然后,他们将遵循以下方法之一:
Alice 将纯文本消息和哈希消息(数字签名)发送到 Bob。 Bob 接收并哈希消息,并将他的哈希值与他从 Alice 收到的哈希值进行比较。 如果哈希值相同,则不会更改消息。 如果值不相同,则消息在 Alice 编写后被更改。
遗憾的是,此方法不建立发送方的真实性。 任何人都可以模拟 Alice 并向 Bob 发送消息。 他们可以使用相同的哈希算法对消息进行签名,并且 Bob 可以确定消息是否与其签名匹配。 这是中间人攻击的一种形式。 有关详细信息,请参阅 加密下一代(CNG)安全通信示例。
Alice 通过不安全的公共通道将纯文本消息发送到 Bob。 她通过安全的专用通道将哈希消息发送到 Bob。 Bob 接收纯文本消息,对其进行哈希处理,并将哈希与专用交换哈希进行比较。 如果哈希匹配,Bob 知道两件事:
消息未更改。
邮件的发送方(Alice)是真实的。
为使此系统发挥作用,Alice 必须对 Bob 之外的所有方隐藏她的原始哈希值。
Alice 通过不安全的公共通道将纯文本消息发送到 Bob,并将哈希消息放置在她可公开查看的网站上。
此方法通过阻止任何人修改哈希值来防止消息篡改。 尽管消息及其哈希可由任何人读取,但哈希值只能由 Alice 更改。 想要模拟 Alice 的攻击者需要访问 Alice 的网站。
上述方法都不会阻止某人阅读 Alice 的消息,因为它们以纯文本形式传输。 完全安全性通常需要数字签名(消息签名)和加密。
.NET 提供实现哈希算法的以下类:
.NET 还提供 MD5 和 SHA1。 但 MD5 和 SHA-1 算法被发现不安全,现在建议改用 SHA-2。 SHA-2 包括 SHA256、SHA384 和 SHA512。
随机数生成
随机数生成是许多加密作不可或缺的一部分。 例如,加密密钥需要尽可能随机,以便无法重现它们。 加密随机数生成器必须生成计算上无法预测的输出,其概率大于一半。 因此,预测下一个输出位的任何方法都不能比随机猜测更好。 .NET 中的类使用随机数生成器来生成加密密钥。
该 RandomNumberGenerator 类是随机数生成器算法的实现。
ClickOnce 清单
通过以下加密类,可以获取和验证有关使用 ClickOnce 技术部署的应用程序的清单签名的信息:
使用ManifestSignatureInformation方法重载时,VerifySignature 类会获取有关清单签名的信息。
可以使用 ManifestKinds 枚举指定要验证的配置文件。 验证的结果是 SignatureVerificationResult 的枚举值之一。
ManifestSignatureInformationCollection 类提供一个只读集合,其中包含已验证签名的 ManifestSignatureInformation 对象。
此外,以下类提供特定的签名信息:
StrongNameSignatureInformation 包含清单的强名称签名信息。
AuthenticodeSignatureInformation 表示清单的 Authenticode 签名信息。
TimestampInformation 包含有关验证码签名上的时间戳的信息。
TrustStatus 提供了一种简单的方法来检查验证码签名是否受信任。
下一代加密技术 (CNG) 类
下一代加密技术 (CNG) 类提供了围绕本机 CNG 函数的托管包装。 (CNG 是 CryptoAPI 的替代者。这些类具有“Cng”作为其名称的一部分。 CNG 包装器类的核心是 CngKey 密钥容器类,它抽象化 CNG 密钥的存储和使用。 此类允许安全地存储密钥对或公钥并使用简单的字符串名称对其进行引用。 基于 ECDsaCng 椭圆曲线的签名类和 ECDiffieHellmanCng 加密类可以使用 CngKey 对象。
此类 CngKey 用于各种附加操作,包括打开、创建、删除和导出密钥。 它还提供对直接调用本机函数时要使用的基础密钥句柄的访问权限。
.NET 还包括各种 CNG 支持类,例如:
CngProvider 维护密钥存储提供程序。
CngAlgorithm 维护 CNG 算法。
CngProperty 维护常用的关键属性。
另请参阅
- 加密模型 - 描述如何在基类库中实现加密。
- 跨平台加密
- 使用填充对 CBC 模式对称解密的漏洞进行计时
- ASP.NET 核心数据保护