scrypt.go 1.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. package crypto
  2. import (
  3. "crypto/rand"
  4. "crypto/subtle"
  5. "errors"
  6. "golang.org/x/crypto/scrypt"
  7. "io"
  8. )
  9. const (
  10. // the salt is a random number of length 8
  11. saltSize = 8
  12. // scrypt key = salt + scrypt, length:40 = 8 + 32
  13. scryptKeySize = 40
  14. )
  15. var (
  16. ErrInvalidLength = errors.New("invalid scrypt key length")
  17. ErrMismatchedPassword = errors.New("password does not match scrypt key")
  18. )
  19. func Scrypt(password string) []byte {
  20. salt := make([]byte, saltSize)
  21. if _, err := io.ReadFull(rand.Reader, salt); err != nil {
  22. panic(err)
  23. }
  24. // The recommended parameters for interactive logins as of 2017 are N=32768, r=8 and p=1.
  25. sk, err := scrypt.Key([]byte(password), salt, 32768, 8, 1, 32)
  26. if err != nil {
  27. panic(err)
  28. }
  29. key := append(salt, sk...)
  30. if len(key) != scryptKeySize {
  31. panic("invalid length")
  32. }
  33. return key
  34. }
  35. func VerifyScrypt(password string, scryptKey []byte) (bool, error) {
  36. if len(scryptKey) != scryptKeySize {
  37. return false, ErrInvalidLength
  38. }
  39. salt := scryptKey[:saltSize]
  40. // The recommended parameters for interactive logins as of 2017 are N=32768, r=8 and p=1.
  41. sk, err := scrypt.Key([]byte(password), salt, 32768, 8, 1, 32)
  42. if err != nil {
  43. panic(err)
  44. }
  45. if subtle.ConstantTimeCompare(sk, scryptKey[saltSize:]) == 1 {
  46. return true, nil
  47. }
  48. return false, ErrMismatchedPassword
  49. }