适用于:SQL Server
Azure SQL 数据库
Azure SQL 托管实例
本文介绍加密算法和机制,用于派生在 SQL Server 和 Azure SQL 数据库 中的 Always Encrypted 功能中使用的加密材料。 这些算法适用于 Always Encrypted 的所有版本和发行版;无论是否使用安全隔区,Always Encrypted 均采用相同的加密算法。
密钥、密钥存储和密钥加密算法
始终加密使用两种类型的密钥:列主密钥和列加密密钥。
列主密钥 (CMK) 是对密钥进行加密的密钥(例如,用于加密其他密钥的密钥),它始终处于客户端的控制之下,并且存储在外部密钥存储中。 支持 Always Encrypted 的客户端驱动程序通过 CMK 存储提供程序与密钥存储交互,而该提供程序要么是驱动程序库的一部分(Microsoft/系统提供程序),要么是客户端应用程序的一部分(自定义提供程序)。 客户端驱动程序库目前包括用于 Windows 证书存储 和硬件安全模块 (HSM) 的 Microsoft 密钥存储提供程序。 有关提供程序的当前列表,请参阅CREATE COLUMN MASTER KEY(Transact-SQL)。 应用程序开发人员可以为任意存储库提供自定义的提供程序。
列加密密钥 (CEK) 是受 CMK 保护的内容加密密钥(例如,用于保护数据的密钥)。
所有 Microsoft CMK 存储提供程序都通过将 RSA 与最佳非对称加密填充 (RSA-OAEP) 配合使用来加密 CEK。 支持 Microsoft 加密 API 的密钥存储提供程序:.NET Framework 中的下一代加密技术 (CNG) (SqlColumnEncryptionCngProvider Class) 使用 A.2.1 节中 RFC 8017 指定的默认参数。 这些默认参数使用 SHA-1 哈希函数和 SHA-1 附带的 MGF1 掩码生成函数。 其他所有密钥存储提供程序都使用 SHA-256。
Always Encrypted 在内部使用经过 FIPS 140-2 验证的加密模块。
数据加密算法
始终加密使用 AEAD_AES_256_CBC_HMAC_SHA_256 算法来加密数据库中的数据。 AEAD 代表与关联数据的经过身份验证的加密; HMAC 代表基于哈希的消息身份验证代码; MAC 表示消息身份验证代码。
AEAD_AES_256_CBC_HMAC_SHA_256 派生自 IETF 规范草案。 它使用带关联数据的认证加密方案,遵循“先加密后计算消息认证码(MAC)”的方法。 也就是说,首先加密纯文本,然后基于生成的密码文本生成 MAC。
为了掩盖模式,AEAD_AES_256_CBC_HMAC_SHA_256 使用密码块链接(CBC)工作模式,其中一个称为初始化向量(IV)的初始值会被输入到系统中。 可以在 美国国家标准与技术研究所(NIST)找到 CBC 模式的完整说明。
AEAD_AES_256_CBC_HMAC_SHA_256 将使用下列步骤计算给定纯文本值的密码文本值。
步骤 1:生成初始化向量 (IV)
始终加密支持 AEAD_AES_256_CBC_HMAC_SHA_256 的两种变体:
具有随机性
具有确定性
在随机加密中,IV 是随机生成的。 结果是,每次加密相同的纯文本,将生成不同的密码文本,可以防止任何信息泄露。
When using randomized encryption: IV = Generate cryptographically random 128bits
对于确定性加密,不会随机生成 IV,而是使用以下算法从纯文本值派生:
When using deterministic encryption: IV = HMAC-SHA-256( iv_key, cell_data ) truncated to 128 bits.
其中 iv_key 按以下方式派生自 CEK:
iv_key = HMAC-SHA-256(CEK, "Microsoft SQL Server cell IV key" + algorithm + CEK_length)
根据初始向量(IV)的需求,会截断 HMAC 值以适应一个数据块的大小。 因此,确定加密始终会为给定纯文本值生成相同的已加密文本,从而能够通过比较其对应的已加密文本值推断两个纯文本值是否相等。 有限的信息泄露允许数据库系统支持对加密的列值的相等性比较。
与其他替代方案相比(例如使用预定义的 IV 值),确定性加密在掩盖模式方面更有效。
步骤 2:计算AES_256_CBC密码文本
对于 Always Encrypted 的 AEAD_AES_256_CBC_HMAC_SHA_256 算法,在计算步骤 1 中的 IV 后,将生成 AES_256_CBC 密码文本:
aes_256_cbc_ciphertext = AES-CBC-256(enc_key, IV, cell_data) with PKCS7 padding.
其中加密密钥 (enc_key) 派生自列加密密钥 (CEK),如下所示:
enc_key = HMAC-SHA-256(CEK, "Microsoft SQL Server cell encryption key" + algorithm + CEK_length )
步骤 3:计算 MAC
对于 Always Encrypted 的 AEAD_AES_256_CBC_HMAC_SHA_256 算法,MAC(消息验证码)是使用从列加密密钥(CEK)派生的 mac_key,根据版本字节、IV(来自步骤 1)和 AES_256_CBC 密文(来自步骤 2)计算得出的:
MAC = HMAC-SHA-256(mac_key, versionbyte + IV + Ciphertext + versionbyte_length)
其中:
versionbyte = 0x01 and versionbyte_length = 1
mac_key = HMAC-SHA-256(CEK, "Microsoft SQL Server cell MAC key" + algorithm + CEK_length)
步骤 4:串联
对于 Always Encrypted 的 AEAD_AES_256_CBC_HMAC_SHA_256 算法,最终加密值是通过连接算法版本字节、MAC(从步骤 3)、IV(从步骤 1)和AES_256_CBC密码文本(从步骤 2) 生成的:
aead_aes_256_cbc_hmac_sha_256 = versionbyte + MAC + IV + aes_256_cbc_ciphertext
密码文本长度
AEAD_AES_256_CBC_HMAC_SHA_256 已加密文本的特定组件的长度是(以字节为单位):
| 组件 | 大小(字节) |
|---|---|
versionbyte |
1 |
MAC |
32 |
IV |
16 |
aes_256_cbc_ciphertext |
(FLOOR(DATALENGTH(cell_data) / block_size) + 1) * block_size,其中 block_size 为 16 个字节, cell_data 是纯文本值。 最小大小 aes_256_cbc_ciphertext 为一个块(16 个字节)。 |
因此,可以使用以下公式计算加密给定纯文本值 (cell_data) 生成的密码文本长度:
1 + 32 + 16 + (FLOOR(DATALENGTH(cell_data)/16) + 1) * 16
例如:
4 个字节长度的 int 纯文本值加密后变成 65 字节长度的二进制值。
加密后,2,000 字节长 nchar(1000) 纯文本值将成为 2,065 字节长的二进制值。
密码文本长度取决于源数据类型。 对于固定长度类型,结果是常量;对于可变长度类型(char、ncharvarcharnvarchar、、binary、),varbinary请使用上述公式。 标记为 N/A 的类型无法使用 Always Encrypted 进行加密。 下表包含数据类型和每种类型的密码文本长度的完整列表。
| 数据类型 | 密码文本长度 [字节] |
|---|---|
| bigint | 65 |
| binary | 视情况而定。 使用上面的公式。 |
| bit | 65 |
| char | 有所不同。 使用上面的公式。 |
| date | 65 |
| datetime | 65 |
| datetime2 | 65 |
| datetimeoffset | 65 |
| 十进制 | 81 |
| float | 65 |
| 地理 | N/A(不支持) |
| geometry | N/A(不支持) |
| hierarchyid | N/A(不支持) |
| image | N/A(不支持) |
| int | 65 |
| money | 65 |
| nchar | 各不相同。 使用上面的公式。 |
| ntext | N/A(不支持) |
| numeric | 81 |
| nvarchar | 各不相同。 使用上面的公式。 |
| 真实 | 65 |
| smalldatetime | 65 |
| smallint | 65 |
| smallmoney | 65 |
| sql_variant | N/A(不支持) |
| sysname | N/A(不支持) |
| text | N/A(不支持) |
| time | 65 |
|
timestamp (rowversion) |
N/A(不支持) |
| tinyint | 65 |
| uniqueidentifier | 81 |
| varbinary | 各不相同。 使用上面的公式。 |
| varchar | 各不相同。 使用上面的公式。 |
| xml | N/A(不支持) |
.NET 参考
有关本文讨论的算法的详细信息,请参阅 .NET Reference 中的 SqlAeadAes256CbcHmac256Algorithm.cs、SqlColumnEncryptionCertificateStoreProvider.cs 和 SqlColumnEncryptionCngProvider.cs 文件。