是否可以通过明文类型确定 ENCRYPTBYKEY 最大返回值?

Posted

技术标签:

【中文标题】是否可以通过明文类型确定 ENCRYPTBYKEY 最大返回值?【英文标题】:Is it possible to determine ENCRYPTBYKEY maximum returned value by the clear text type? 【发布时间】:2018-08-28 00:37:36 【问题描述】:

我将加密现有表中的几个字段。基本上,将使用以下加密技术:

CREATE MASTER KEY ENCRYPTION
BY PASSWORD = 'sm_long_password@'
GO

CREATE CERTIFICATE CERT_01
WITH SUBJECT = 'CERT_01'
GO

CREATE SYMMETRIC KEY SK_01
WITH ALGORITHM = AES_256 ENCRYPTION
BY CERTIFICATE CERT_01
GO


OPEN SYMMETRIC KEY SK_01 DECRYPTION
BY CERTIFICATE CERT_01

SELECT ENCRYPTBYKEY(KEY_GUID('SK_01'), 'test')

CLOSE SYMMETRIC KEY SK_01

DROP SYMMETRIC KEY SK_01
DROP CERTIFICATE CERT_01
DROP MASTER KEY

ENCRYPTBYKEY 返回 varbinary,最大大小为 8,000 字节。知道要加密的表字段(例如:nvarchar(128)varchar(31)bigint)如何定义新的varbinary 类型长度?

【问题讨论】:

【参考方案1】:

你可以看到完整的规范here

让我们计算一下:

16字节密钥UID _4字节头 16 字节 IV(对于 AES,16 字节分组密码)

再加上加密消息的大小:

_4字节幻数 _2字节完整性字节长度 _0 bytes 完整性字节(警告:可能在表中放错了) _2字节(明文)消息长度 _m字节(明文)消息 CBC 填充字节

CBC 填充字节应按以下方式计算:

16 - ((m + 4 + 2 + 2) % 16)

因为总是应用填充。这将导致 1..16 范围内的填充字节数。一个偷偷摸摸的捷径是只在总数中添加 16 个字节,但这可能意味着您要指定最多 15 个从未使用过的字节。


我们可以将其缩短为 36 + 8 + m + 16 - ((m + 8) % 16)60 + m - ((m + 8) % 16。或者,如果您使用上面指定的小技巧并且不关心浪费的字节:76 + m 其中 m 是消息输入。


注意事项:

注意头中的第一个字节包含方案的版本号;如果使用不同的内部消息格式或加密方案,此答案是否 notcannot 指定将添加或删除多少字节; 强烈建议您使用完整性字节,以防您希望保护您的数据库字段不被更改(保持帐户中的金额保密不如确保金额无法更改重要)。 页面上的示例假定文本字符采用单字节编码。

【讨论】:

请在继续之前确认这是正确的,我是加密专家,而不是数据库专家。 我只是想知道这部分:using integrity bytes is highly recommended - 你能给我一个链接,我可以在其中找到更多详细信息。 这有点通用:如果您使用对称密钥保护您的数据免于机密性,那么您不妨保护它免受更改(但请注意,交换它可能仍然是可能的)。参见例如 GCM 等 authenticated 密码模式的巨大进展,例如在 TLS 1.3(最新的 SSL 草案)中。是否需要取决于用例和威胁模型。您不希望有人更改银行帐户的值,但即使您可以更改密码,您也无法窃取密码。 那么计算结果检查了吗?我想他们确实接受了? 是的,我已经使用 ASCII 和 Unicode 数据进行了测试。一切都是正确的。我无法加密数字或日期,但这是 T-SQL 函数的限制。【参考方案2】:

根据 SQL Server 2008 中的一些测试,以下公式似乎有效。注意@ClearText 是 VARCHAR():

52 + (16 * ( ((LEN(@ClearText) + 8)/ 16) ) )

这与 Maarten Bodewes 的答案大致兼容,只是我的测试显示 DATALENGTH(myBinary) 始终采用 52 + (z * 16) 的形式,其中 z 是一个整数。

LEN(myVarCharString)   DATALENGTH(encryptedString)
--------------------   -----------------------------------------
 0 through  7          usually 52, but occasionally 68 or 84 
 8 through 23          usually 68, but occasionally 84
24 through 39          usually 84
40 through 50          100

“myVarCharString”是定义为 VARCHAR(50) 的表列。该表包含 150,000 条记录。提到“偶尔”是10,000条记录中大约有1条会被撞到更高存储桶的实例;很奇怪。对于 24 或更高的 LEN(),没有足够的记录来获取奇怪的异常。

这是一些 Perl 代码,它采用“myVarCharString”的建议长度作为来自终端的输入,并为 EncryptByKey() 结果生成预期的大小。函数“int()”等价于“Math.floor()”。

while($len = <>)  
  print 52 + ( 16 * int( ($len+8) / 16 ) ),"\n";

您可能希望使用此公式来计算大小,然后添加 16 以考虑异常情况。

【讨论】:

以上是关于是否可以通过明文类型确定 ENCRYPTBYKEY 最大返回值?的主要内容,如果未能解决你的问题,请参考以下文章

linux桌面系统使用明文ssh密码登陆远程服务器

知道明文和密文,如何确定是啥加密算法

是否可以确定一个类型是否是作用域枚举类型?

是否可以确定一个类型是否是作用域枚举类型?

是否可以确定 lambda 的参数类型和返回类型?

是否可以确定麦克风类型?