Database 在另一个表中存储加密的密码密钥是一个好主意吗?
我正在从事一个项目,在这个项目中,我有一些有价值的信息必须存储在“members”表中。表结构如下所示: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 |
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是更好的选择。