将加密的密钥存储在另一个表中是个好主意吗?

时间:2013-09-13 13:46:41

标签: database security encryption key aes

我正在开展一个项目,我的宝贵信息必须存储在表'成员'中。表结构如下所示:

id | username | password | salt | last_name 
———|——————————|——————————|——————|———————————
 1 | VARCHAR  |   HASH   | CHAR |    BLOB   
 2 | VARCHAR  |   HASH   | CHAR |    BLOB   
 3 | VARCHAR  |   HASH   | CHAR |    BLOB   
 4 | VARCHAR  |   HASH   | CHAR |    BLOB   
 5 | VARCHAR  |   HASH   | CHAR |    BLOB   

在此示例中,last_name使用密钥加密。该密钥存储在表'keys'中:

id | key  
———|—————— 
 1 | BLOB 
 2 | BLOB 
 3 | BLOB 
 4 | BLOB 
 5 | BLOB 

这些密钥也使用另一个密钥加密,该密钥源自未散列的密码,id和用户名。

我认为这是保存,因为如果数据库被盗,盗贼无法导出表'密钥'中的密钥,最终无法导出解密last_name

我想确定这是否真的是保存,或者是否有另一种存储密钥的方法。

1 个答案:

答案 0 :(得分:1)

这称为密钥包装,是的,它是安全的,但是当你加密密钥时,你应该使用专门为它设计的密码。 This question对于原因有一个不错的解释。

不确定您使用的语言是什么,但在Java中,您可以这样做:

Key rootKey = new SecretKeySpec(keyBytes, "AES");
KeyGenerator generator = KeyGenerator.getInstance("AES");
generator.init(128);
Key keyToWrap = generator.generateKey();

Cipher cipher = Cipher.getInstance("AESWRAP");
cipher.init(Cipher.WRAP_MODE, rootKey);
byte[] wrappedKey = cipher.wrap(keyToWrap);

Cipher uncipher = Cipher.getInstance("AESWRAP");
uncipher.init(Cipher.UNWRAP_MODE, rootKey);
Key unwrappedKey = uncipher.unwrap(wrappedKey, "AES", Cipher.SECRET_KEY);

还要确保使用良好的密钥派生函数(如SCrypt)来派生每个用户的根密钥。 Bouncy Castle具有Java和C#的SCrypt实现,以及它自己的密钥包装实现。或者您可以找到PHP SCrypt实现here

请记住但是,根据您的方案,如果用户忘记了密码,您将无法恢复其加密数据,因为其根密钥是从密码派生的。