-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
crypto/pbkdf2: add package #69488
Comments
Related Issues and Documentation (Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.) |
My one hangup about this is that new projects shouldn't be using PBKDF2 without a good reason. There are significantly better password-based KDFs, like Argon2 or even scrypt. IMO, it's misleading to move this into the stdlib without updating the docs to point people to better algorithms. |
Reasons aside, pbkdf2 is much more popular that scrypt and argon2, at least if we look the number of times the corresponding golang.org/x/crypto package is imported. As of writing this, pbkdf2 is imported by 7081 modules, scrypt 3227 modules and argon2 1559 modules. Having said this, it is fine for me to add any doc explaining better alternatives with the corresponding reasoning. |
We've had higher level discussions of providing a more opaque password hashing API, wherein you just have a password you want to hash, and we return what we consider a secure hash (and also implement the verification side to transparently support multiple hashes, so we can easily rotate what we return). I think that is the long term solution to these kinds of problems where people are still using an older, less ideal method simply because they don't know they should update. In the short-term adding pbkdf2 to the standard library seems mostly fine to me. In the long term we'll probably want to continue to provide these primitives anyway, since people will continue to need them for backwards and third-party compatibility. I think the other option is to leave it in x/crypto as one of the "frozen" libraries we don't expect to see any further development. There are currently no other open issues for the library (and only 2 closed historical issues), so perhaps that would be reasonable if we don't expect any new API additions, and don't have any plans to make any other substantial changes to the package. If we do add it, we should definitely add a note to the documentation though pointing out you should only be using this for compat reasons, and pointing to the better choices. cc @FiloSottile |
Thanks for the insights @rolandshoemaker.
In the issue description I mentioned a small API change that could make
|
Oh sorry, I somehow completely glossed over this while reading through this. In that case I think it's reasonable to move into the standard library with these specific changes. |
Would such bad inputs qualify for a panic, rather than an error? (My understanding is that these are programming mistakes, not user input, and thus it might be better to panic.) |
This proposal has been added to the active column of the proposals project |
For backwards compatibility, I think we need an "escape hatch" to derive a key using older, non-secure parameters. For instance, I have backups written with software that predates the SP 800-132 recommendations that I would like to still be able to read using modern tools. |
There are two ways to deal with this. One is that we always compute and return the hash, but also return an error of a particular type if the parameters aren't secure. That way the caller can check for and discard that error if necessary. Another option would be a GODEBUG. (Possibly we do both and the GODEBUG would simply suppress the error return.) |
These are NIST recommendations and I am not sure we should enforce them across the board. For example salt-less PBKDF makes sense in some settings. This is what I guess adding the error return makes sense for future-proofing, although it makes switching package harder, but I don't think we need to think about GODEBUGs and new errors. Since we're breaking the API anyway, should we move
Also, like in #61477 (comment), should we make it generic over And maybe |
I'm fine not implementing those FIPS restrictions by default if they are not mandatory. If we have the error return then we can implement whatever opt-in or opt-out requirements we want in the future.
Good point, agree we should do this, else it will cause confusion when working with different KDFs.
I don't have an opinion on these changes. Both would work for me. |
In that case, the API would be func Key[H hash.Hash](h func() H, password, salt []byte, iter, keyLen int) ([]byte, error) right? This seems pretty good to me. |
This API looks good to me. I looked at the usage of generics, and it is only being used for type-checking, not in a way that will trigger multiple copies of the code. One small note. I'd like to see us use good names for type parameters much the same way we use good names for function arguments. For containers type T may be a special case (even then I am not sure), but certainly the rest of the time, let's use names that actually make sense in error messages. In this case, s/H/Hash/. |
Taking the opportunity to disambiguate password and salt with types, let's do
|
Whatever type we decide for salt should be the same as in #61477, right? |
See #61477 (comment) |
Just a minor nit: in this proposal the key length argument is |
Based on the discussion above, this proposal seems like a likely accept. The proposal is to add a new // Key derives a key from the password, salt and iteration count,
// returning a []byte of length keyLength that can be used as cryptographic key.
// The key is derived based on the method described as PBKDF2 with the
// HMAC variant using the supplied hash function.
func Key[Hash hash.Hash](h func() Hash, password string, salt []byte, iter, keyLength int) ([]byte, error) |
Change https://go.dev/cl/628135 mentions this issue: |
No change in consensus, so accepted. 🎉 The proposal is to add a new // Key derives a key from the password, salt and iteration count,
// returning a []byte of length keyLength that can be used as cryptographic key.
// The key is derived based on the method described as PBKDF2 with the
// HMAC variant using the supplied hash function.
func Key[Hash hash.Hash](h func() Hash, password string, salt []byte, iter, keyLength int) ([]byte, error) |
This commit imports the x/crypto/pbkdf2 package as described in the linked proposal. The code is unchanged with the exception of a few small updates to reflect feedback from the proposal comment period: * the Key function is made generic over a hash.Hash * the h function is moved to be the first argument * keyLen is renamed to keyLength * an error return is added * the unit tests were moved to the pbkdf2_test package Updates #69488 Change-Id: If72f854daeb65a5c7fbe45ebd341e63a33340624 Reviewed-on: https://go-review.googlesource.com/c/go/+/628135 Reviewed-by: Dmitri Shuralyov <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Russ Cox <[email protected]>
I think this can be closed since #628135 landed - I used the wrong linkage in the description. |
Important
Nov 20, 2024: The latest version of the proposal is here.
Proposal Details
I propose to move the golang.org/x/crypto/pbkdf2 package into the standard library with the name
crypto/pbkdf2
. This proposal is a #65269 spin off, as requested by the following comment from @rsc:pbkdf2
is a low-hanging fruit here as it only exports a single function. I propose to move it to the standard library as is, just adding an error return parameter in case we want to implement some additional parameter validation in the future (e.g. minimum salt length or minimum iterations). The proposed API looks like this:The
pbkdf2.Key
function is enough to cover most pbkdf2 use cases. As a data point, OpenSSL exports the PKCS5_PBKDF2_HMAC function, accepting the same inputs aspbkdf2.Key
.@golang/security
The text was updated successfully, but these errors were encountered: