Aes-Gcm / Aes-Cbc - 数据库存储 - 列设计
Aes-Gcm / Aes-Cbc - Database Storage - Column design
我的问题是关于我实际需要在数据库中存储什么重新加密的值,以及如何将其用于 GCM 的随机数。
为了参考,这两个答案提供了用于加密数据的示例代码:
Cbc and gcm.
据我了解,CBC 要求 IV 完全随机。我知道对于 CBC(以及所有加密),Key/IV 应该始终是唯一的。如果重复,则 CBC 为 'bad',如果使用 GCM,则为根本缺陷。但是 GCM 不需要它是完全随机的,只要它从不重复即可。
基于这些假设,我们计划在应用程序的某处设置一个 'key'(即将密钥与数据库中的加密数据分开)。我们将每 'n' 个月滚动一次密钥,并且在生成新密钥之前仅将其用于 'x' 次加密(限制使用范围等),但是,我们将使用相同的 'key' 两个或多个记录。因此,独特的 key/iv 开始发挥作用。
注意:我们需要能够稍后再次读取数据并'use'它。这不是一种加密方式。
在设计数据库时,我们将使用类似于以下的列。
CBC 模式的 DB 列(我在堆栈溢出时看到类似的东西...抱歉找不到 link):
- ID(主键,整数)(唯一)
- 加密值
- 盐
- 迭代次数
- (其他...标准内容,例如创建日期等)
Gcm 模式的 Db 列:
- ID(主键,整数)(唯一)
- 加密值
- 关联文本
- (其他...标准内容,例如创建日期等)
IV/Nonce 处理问题
对于 CBC 模式,我们只是打算使用例如Rfc2898DeriveBytes
并从中获取 IV 而不是存储它。
关于 GCM 模式,这里的想法是执行以下操作:
- 先保存记录,然后'get'行的id
- 将行 ID 转换为字节 [16]... 例如(仅供示例...)
var rowID = 123456789.ToString();
var tempByte = new List<byte>(16);
tempByte.AddRange
(123456789.ToString()
.Select(Convert.ToByte));
if (rowID.Length < 16)
{
for (var i = 0; i < (16 - rowID.Length); i++)
{
// Note: something to fill the rest.....
var someNewByteFromSecureRandom = new[] {Convert.ToByte(1)};
tempByte.Add(someNewByteFromSecureRandom[0]);
}
}
- 将加密数据保存到行中。
这样,随机数对于 GCM 加密将始终是唯一的。即使我们总是使用同一个键,key/iv 也永远不会重复。 (注意:据我们了解,这种方法不适用于 CBC,因为它要求 iv 是真正随机的,而不是计数器)
基本上,这两种方法都有问题吗? (在使用 GCM 方法大纲获取随机数时忽略记录的明显双重保存 (insert/update))。我们是在保存不应该保存的东西吗?我们不是在保存我们应该保存的东西吗?
假设:您只保护静态数据,即不考虑在使用数据库时对数据的主动攻击。
- CBC 要求 IV 对攻击者随机出现,CBC 可以使用加密计数器(行 ID)作为 IV;
- 要使用行 ID 作为随机数,您需要开始 带有行 ID 的 IV(最右边的字节)(转换为 12 字节无符号大端数)-为了最大的兼容性,最左边的字节应该保持为空
- 如果您已经拥有密钥,CBC 不需要 PBKDF2(因此不需要盐或迭代计数)- 您可以只存储随机 IV 而不是盐
- "Associated Text" 本身没有任何意义。 GCM 将附加关联数据(或 AAD)作为输入参数。因此,AAD 只是数据库中要包含在身份验证标记中的任何数据。 GCM 已将 IV 包含在身份验证标记中,因此您不必包含行 ID;
- CBC 对于 静态数据 足够了,因为没有人应该能够更改数据(这将是一个活跃的攻击者,排除了静态数据);也就是说,GCM 确实会捕获任何错误的 key/wrong 数据错误,因此它可用于简化应用程序的错误处理。
请注意,使用 12 字节的随机数会将明文限制为 2^36 字节 (64 GiB)。这对数据库条目来说应该不是问题(我希望如此)。如果你遇到这么大的明文,你可能会抛出错误或运行时异常。
我的问题是关于我实际需要在数据库中存储什么重新加密的值,以及如何将其用于 GCM 的随机数。
为了参考,这两个答案提供了用于加密数据的示例代码: Cbc and gcm.
据我了解,CBC 要求 IV 完全随机。我知道对于 CBC(以及所有加密),Key/IV 应该始终是唯一的。如果重复,则 CBC 为 'bad',如果使用 GCM,则为根本缺陷。但是 GCM 不需要它是完全随机的,只要它从不重复即可。
基于这些假设,我们计划在应用程序的某处设置一个 'key'(即将密钥与数据库中的加密数据分开)。我们将每 'n' 个月滚动一次密钥,并且在生成新密钥之前仅将其用于 'x' 次加密(限制使用范围等),但是,我们将使用相同的 'key' 两个或多个记录。因此,独特的 key/iv 开始发挥作用。
注意:我们需要能够稍后再次读取数据并'use'它。这不是一种加密方式。
在设计数据库时,我们将使用类似于以下的列。
CBC 模式的 DB 列(我在堆栈溢出时看到类似的东西...抱歉找不到 link):
- ID(主键,整数)(唯一)
- 加密值
- 盐
- 迭代次数
- (其他...标准内容,例如创建日期等)
Gcm 模式的 Db 列:
- ID(主键,整数)(唯一)
- 加密值
- 关联文本
- (其他...标准内容,例如创建日期等)
IV/Nonce 处理问题
对于 CBC 模式,我们只是打算使用例如Rfc2898DeriveBytes
并从中获取 IV 而不是存储它。
关于 GCM 模式,这里的想法是执行以下操作:
- 先保存记录,然后'get'行的id
- 将行 ID 转换为字节 [16]... 例如(仅供示例...)
var rowID = 123456789.ToString();
var tempByte = new List<byte>(16);
tempByte.AddRange
(123456789.ToString()
.Select(Convert.ToByte));
if (rowID.Length < 16)
{
for (var i = 0; i < (16 - rowID.Length); i++)
{
// Note: something to fill the rest.....
var someNewByteFromSecureRandom = new[] {Convert.ToByte(1)};
tempByte.Add(someNewByteFromSecureRandom[0]);
}
}
- 将加密数据保存到行中。
这样,随机数对于 GCM 加密将始终是唯一的。即使我们总是使用同一个键,key/iv 也永远不会重复。 (注意:据我们了解,这种方法不适用于 CBC,因为它要求 iv 是真正随机的,而不是计数器)
基本上,这两种方法都有问题吗? (在使用 GCM 方法大纲获取随机数时忽略记录的明显双重保存 (insert/update))。我们是在保存不应该保存的东西吗?我们不是在保存我们应该保存的东西吗?
假设:您只保护静态数据,即不考虑在使用数据库时对数据的主动攻击。
- CBC 要求 IV 对攻击者随机出现,CBC 可以使用加密计数器(行 ID)作为 IV;
- 要使用行 ID 作为随机数,您需要开始 带有行 ID 的 IV(最右边的字节)(转换为 12 字节无符号大端数)-为了最大的兼容性,最左边的字节应该保持为空
- 如果您已经拥有密钥,CBC 不需要 PBKDF2(因此不需要盐或迭代计数)- 您可以只存储随机 IV 而不是盐
- "Associated Text" 本身没有任何意义。 GCM 将附加关联数据(或 AAD)作为输入参数。因此,AAD 只是数据库中要包含在身份验证标记中的任何数据。 GCM 已将 IV 包含在身份验证标记中,因此您不必包含行 ID;
- CBC 对于 静态数据 足够了,因为没有人应该能够更改数据(这将是一个活跃的攻击者,排除了静态数据);也就是说,GCM 确实会捕获任何错误的 key/wrong 数据错误,因此它可用于简化应用程序的错误处理。
请注意,使用 12 字节的随机数会将明文限制为 2^36 字节 (64 GiB)。这对数据库条目来说应该不是问题(我希望如此)。如果你遇到这么大的明文,你可能会抛出错误或运行时异常。