-
Notifications
You must be signed in to change notification settings - Fork 343
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(general): user password hashing and key derivation helpers (#…
…3821) Code movement and simplification, no functional changes. Objectives: - Allow callers specifying the needed key (or hash) size, instead of hard-coding it in the registered PBK derivers. Conceptually, the caller needs to specify the key size, since that is a requirement of the (encryption) algorithm being used in the caller. Now, the code changes here do not result in any functional changes since the key size is always 32 bytes. - Remove a global definition for the default PB key deriver to use. Instead, each of the 3 use case sets the default value. Changes: - `crypto.DeriveKeyFromPassword` now takes a key size. - Adds new constants for the key sizes at the callers. - Removes the global `crypto.MasterKeySize` const. - Removes the global `crypto.DefaultKeyDerivationAlgorithm` const. - Adds const for the default derivation algorithms for each use case. - Adds a const for the salt length in the `internal/user` package, to ensure the same salt length is used in both hash versions. - Unexports various functions, variables and constants in the `internal/crypto` & `internal/user` packages. - Renames various constants for consistency. - Removes unused functions and symbols. - Renames files to be consistent and better reflect the structure of the code. - Adds a couple of tests to ensure the const values are in sync and supported. - Fixes a couple of typos Followups to: - #3725 - #3770 - #3779 - #3799 - #3816 The individual commits show the code transformations to simplify the review of the changes.
- Loading branch information
1 parent
2db8b20
commit ca1962f
Showing
19 changed files
with
184 additions
and
181 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
//go:build !testing | ||
// +build !testing | ||
|
||
package crypto | ||
|
||
import ( | ||
"github.com/pkg/errors" | ||
"golang.org/x/crypto/scrypt" | ||
) | ||
|
||
const ( | ||
// ScryptAlgorithm is the registration name for the scrypt algorithm instance. | ||
ScryptAlgorithm = "scrypt-65536-8-1" | ||
|
||
// The recommended minimum size for a salt to be used for scrypt. | ||
// Currently set to 16 bytes (128 bits). | ||
// | ||
// A good rule of thumb is to use a salt that is the same size | ||
// as the output of the hash function. For example, the output of SHA256 | ||
// is 256 bits (32 bytes), so the salt should be at least 32 random bytes. | ||
// Scrypt uses a SHA256 hash function. | ||
// https://crackstation.net/hashing-security.htm | ||
scryptMinSaltLength = 16 // 128 bits | ||
) | ||
|
||
func init() { | ||
registerPBKeyDeriver(ScryptAlgorithm, &scryptKeyDeriver{ | ||
n: 65536, //nolint:gomnd | ||
r: 8, //nolint:gomnd | ||
p: 1, | ||
minSaltLength: scryptMinSaltLength, | ||
}) | ||
} | ||
|
||
type scryptKeyDeriver struct { | ||
// n scryptCostParameterN is scrypt's CPU/memory cost parameter. | ||
n int | ||
// r scryptCostParameterR is scrypt's work factor. | ||
r int | ||
// p scryptCostParameterP is scrypt's parallelization parameter. | ||
p int | ||
|
||
minSaltLength int | ||
} | ||
|
||
func (s *scryptKeyDeriver) deriveKeyFromPassword(password string, salt []byte, keySize int) ([]byte, error) { | ||
if len(salt) < s.minSaltLength { | ||
return nil, errors.Errorf("required salt size is at least %d bytes", s.minSaltLength) | ||
} | ||
//nolint:wrapcheck | ||
return scrypt.Key([]byte(password), salt, s.n, s.r, s.p, keySize) | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package user | ||
|
||
// DefaultPasswordHashingAlgorithm is the default password hashing scheme for user profiles. | ||
const DefaultPasswordHashingAlgorithm = scryptHashAlgorithm | ||
|
||
// PasswordHashingAlgorithms returns the supported algorithms for user password hashing. | ||
func PasswordHashingAlgorithms() []string { | ||
return []string{scryptHashAlgorithm, pbkdf2HashAlgorithm} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package user | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/kopia/kopia/internal/crypto" | ||
) | ||
|
||
// The password hashing constants defined in this package are used as "lookup | ||
// keys" for the register password-based key derivers in the crypto package. | ||
// This trivial test is a change detector to ensure that the constants defined | ||
// in the user package match those defined in the crypto package. | ||
func TestPasswordHashingConstantMatchCryptoPackage(t *testing.T) { | ||
require.Equal(t, crypto.ScryptAlgorithm, scryptHashAlgorithm) | ||
require.Equal(t, crypto.Pbkdf2Algorithm, pbkdf2HashAlgorithm) | ||
} | ||
|
||
// The passwordHashSaltLength constant defines the salt length used in this | ||
// package for password hashing. This trivial test ensures that this hash length | ||
// meets the minimum requirement for the instantiations of the registered | ||
// password hashers (PB key derivers in the crypto package). | ||
func TestSaltLengthIsSupported(t *testing.T) { | ||
const badPwd = "password" | ||
var salt [passwordHashSaltLength]byte | ||
|
||
for _, h := range PasswordHashingAlgorithms() { | ||
_, err := computePasswordHash(badPwd, salt[:], h) | ||
require.NoError(t, err) | ||
} | ||
} |
Oops, something went wrong.