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

Database 在另一个表中存储加密的密码密钥是一个好主意吗?,database,security,encryption,key,aes,Database,Security,Encryption,Key,Aes,我正在从事一个项目,在这个项目中,我有一些有价值的信息必须存储在“members”表中。表结构如下所示: id | username | password | salt | last_name ———|——————————|——————————|——————|——————————— 1 | VARCHAR | HASH | CHAR | BLOB 2 | VARCHAR | HASH | CHAR | BLOB 3 | VARCHAR |

我正在从事一个项目,在这个项目中,我有一些有价值的信息必须存储在“members”表中。表结构如下所示:

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   
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);
在本例中,
last\u name
使用密钥加密。该键存储在表“键”中:

id | key  
———|—————— 
 1 | BLOB 
 2 | BLOB 
 3 | BLOB 
 4 | BLOB 
 5 | BLOB 
这些密钥还使用另一个密钥加密,该密钥来自未加密的密码、id和用户名

我认为这是节省,因为如果数据库被盗,盗贼就无法派生表“keys”中的密钥,最终也无法派生并解密
姓氏


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

这称为密钥包装,是的,这样做是安全的,但在加密密钥时,应该使用专门为其设计的密码。对原因有一个合理的解释

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

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   
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)派生每个用户的根密钥。具有针对Java和C#的SCrypt实现,以及它自己的密钥封装实现。或者,您可以找到一个PHP SCrypt实现


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

我实际上想使用SHA-512哈希算法的275000次迭代来生成派生密钥(解锁已包装密钥的密钥)。包装密钥由512字节的随机字符组成。SHA-512比SCrypt更容易用GPU优化破解,并且SCrypt的参数允许您调整它使用的CPU数量和内存。您可以选择SHA-512,但SCrypt是更好的选择。