在哪里存储密码?
我正在编写一个 Android 密码管理器应用程序,我想将主密码存储在某个地方,但我不知道在哪里。我是否应该使用我选择的硬编码密码来加密用户给我的主密码,然后将其存储到数据库中?或者我应该做点别的什么?
I am writing an android password manager application and i want to store the master password somewhere but i don't know where. Should i encrypt the master password that the user gives me with a hard coded password that i choose and then store it to the database? or should i do something else?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您永远不应该存储未加密的密码。
对于无法安全加密的密码(因为必须将解密密钥存储在某处),您应该只存储其不可逆的哈希值。
这样,当用户向您提供密码时,您可以将密码与哈希值进行比较。如果匹配,您可以使用给定的密码解密存储的用户:密码对。
PS:不要忘记对哈希加盐,请正确操作。
You should never store unencrypted passwords.
For passwords, that you can't encrypt safely (because you have to store the decryption key somewhere), you should only store a unreversible hash of it.
That way you can compare the password to the hash when the user gives you the password. If it matches, you can decrypt the stored user:password pairs with the given password.
PS: Don't forget to salt the hash and please do it properly.
不,不,一千次不。
如果您被允许查看 GPLv2 代码,请查看 KeePass 源代码。
主密码转换为密钥(基于密码的密钥派生),并且该密钥用于加密和解密各个数据片段(各个密码)。
因此,该过程类似于:
1. 关闭任何可以关闭的交换到磁盘的类型。询问用户主密码。
使用 PBKDF2(HMAC-SHA-256, 主密码, 存储的随机盐*, 2000000, 256) 之类的东西将主密码转换为仅内存中的主加密密钥 - PBKDF2 也称为 RFC2898 和PKCS#5。 HMAC-SHA-256 是哈希函数。主密码是用户输入的任何内容 - 它永远不会以任何形式保存!存储的随机盐是每当选择新的主密码时新鲜生成的 64 位或更大的加密随机值,并保存而不是保存任何形式的主密码。 2000000 是我们要运行 HMAC 的次数,该次数已存储并且应该由用户选择 - 这应该是您可以等待的次数(KeePass 有一个功能可以对它们进行基准测试,并查看有多少次需要 1 秒) - 我建议将其增加到 4 或 5 秒)。 256 是所需输出的位数 - 在这种情况下,我假设您将使用 CAMELLIA-256 或 AES-256 来加密您的密码(只需匹配您的加密函数用于密钥的位数) 。
是的,可以使用 scrypt 或 bcrypt 来代替。
检查主密码是否正确:如果我们要使用现有主密码进入现有数据库,请使用该仅内存密钥来解密一些固定数据,例如“默认”密码。如果值解密为您期望的值,则输入的主密码正确,否则,主密码错误和/或数据库已损坏。如果我们要启动一个新数据库或更改主密码,请加密该“默认”密码并存储加密值。
使用主加密密钥来解密 URL、用户名、注释和其他非密码数据。
仅根据用户的请求使用主加密密钥解密现有密码(但仅限用户请求的精确密码),然后在完成或计时器耗尽后立即用随机垃圾覆盖数据。使用所述主加密密钥加密新密码。
一旦用户完成或计时器耗尽,就用随机垃圾覆盖所有变量(尤其是仅内存中的主加密密钥)。
请注意,您正在存储:
您永远不会存储主密码或密码它的哈希值。您永远不会将主密码、其哈希值、甚至生成的主加密密钥与其他任何内容进行比较。您只需获取主密码并将其转换为主加密密钥,然后使用该密钥来加密或解密数据 - 已知数据(“固定”密码)可让您查看该密钥是否给出了预期结果。当您知道主密码正确时,未知数据(用户输入和关心的所有内容)也会被加密或解密。
No, no, a thousand times no.
If you are allowed to look at GPLv2 code, take a look at the KeePass source code.
The master password is turned into a key (password based key derivation), and that key is used to encrypt and decrypt the individual pieces of data (individual passwords).
Therefore, the process is similar to this:
1. Turn off any kind of swap-to-disk you can turn off. Ask the user for the master password.
Turn the master password into an in-memory-only master encryption key, by using something like PBKDF2(HMAC-SHA-256, master password, stored random salt*, 2000000, 256) - PBKDF2 is also known as RFC2898 and PKCS #5. HMAC-SHA-256 is the hashing function. Master password is whatever the user entered - this is never saved in any form at all! Stored random salt is a 64-bit or larger cryptographically random value generated fresh whenever a new master password is selected, and saved instead of saving any form of the master password whatsoever. 2000000 is the number of times we're going to run the HMAC, which is stored and should be user selectable - this should be as many as you can stand to wait (KeePass has a function to benchmark them and see how many take 1 second - I recommend increasing that to 4 or 5 seconds). 256 is the number of bits of output required - in this case, I'm assuming you're going to use either CAMELLIA-256 or AES-256 to encrypt your passwords (just match how many bits your encryption function uses for the key).
Yes, scrypt or bcrypt can be used instead.
Check to see if the master password was correct: If we're going into an existing database with an existing master password, use that in-memory-only key to decrypt some fixed data, like a 'default' password. If value decrypts to the value you expect, the master password entered was correct, if not, the master password was wrong and/or the database is corrupt. If we're starting a new database or changing the master password, encrypt that 'default' password and store the encrypted value.
Use the master encryption key to decrypt URL's, usernames, notes, and other non-password data.
Use the master encryption key to decrypt existing passwords only per the user's request (but only the precise password the user requested) and then overwrite the data with random garbage as soon as they're done with it or a timer runs out. Encrypt new passwords using said master encryption key.
As soon as the user's done or a timer runs out, overwrite all variables (most especially the in-memory-only master encryption key) with random garbage.
Note you're storing:
You are never, ever storing either the master password or a hash of it. You never ever compare the master password, a hash of it, or even the generated master encryption key to anything else. You only ever take a master password and turn it into a master encryption key, and then use that key to encrypt or decrypt data - known data (the "fixed" password) lets you see if that key gave the expected results. Unknown data (everything the user entered and cares about) is also encrypted or decrypted when you know the master password is correct.