salt.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. // Copyright 2012, Jeramey Crawford <jeramey@antihe.ro>
  2. // Copyright 2013, Jonas mg
  3. // All rights reserved.
  4. //
  5. // Use of this source code is governed by a BSD-style license
  6. // that can be found in the LICENSE file.
  7. package common
  8. import (
  9. "crypto/rand"
  10. "errors"
  11. "strconv"
  12. )
  13. var (
  14. ErrSaltPrefix = errors.New("invalid magic prefix")
  15. ErrSaltFormat = errors.New("invalid salt format")
  16. ErrSaltRounds = errors.New("invalid rounds")
  17. )
  18. // Salt represents a salt.
  19. type Salt struct {
  20. MagicPrefix []byte
  21. SaltLenMin int
  22. SaltLenMax int
  23. RoundsMin int
  24. RoundsMax int
  25. RoundsDefault int
  26. }
  27. // Generate generates a random salt of a given length.
  28. //
  29. // The length is set thus:
  30. //
  31. // length > SaltLenMax: length = SaltLenMax
  32. // length < SaltLenMin: length = SaltLenMin
  33. func (s *Salt) Generate(length int) []byte {
  34. if length > s.SaltLenMax {
  35. length = s.SaltLenMax
  36. } else if length < s.SaltLenMin {
  37. length = s.SaltLenMin
  38. }
  39. saltLen := (length * 6 / 8)
  40. if (length*6)%8 != 0 {
  41. saltLen++
  42. }
  43. salt := make([]byte, saltLen)
  44. rand.Read(salt)
  45. out := make([]byte, len(s.MagicPrefix)+length)
  46. copy(out, s.MagicPrefix)
  47. copy(out[len(s.MagicPrefix):], Base64_24Bit(salt))
  48. return out
  49. }
  50. // GenerateWRounds creates a random salt with the random bytes being of the
  51. // length provided, and the rounds parameter set as specified.
  52. //
  53. // The parameters are set thus:
  54. //
  55. // length > SaltLenMax: length = SaltLenMax
  56. // length < SaltLenMin: length = SaltLenMin
  57. //
  58. // rounds < 0: rounds = RoundsDefault
  59. // rounds < RoundsMin: rounds = RoundsMin
  60. // rounds > RoundsMax: rounds = RoundsMax
  61. //
  62. // If rounds is equal to RoundsDefault, then the "rounds=" part of the salt is
  63. // removed.
  64. func (s *Salt) GenerateWRounds(length, rounds int) []byte {
  65. if length > s.SaltLenMax {
  66. length = s.SaltLenMax
  67. } else if length < s.SaltLenMin {
  68. length = s.SaltLenMin
  69. }
  70. if rounds < 0 {
  71. rounds = s.RoundsDefault
  72. } else if rounds < s.RoundsMin {
  73. rounds = s.RoundsMin
  74. } else if rounds > s.RoundsMax {
  75. rounds = s.RoundsMax
  76. }
  77. saltLen := (length * 6 / 8)
  78. if (length*6)%8 != 0 {
  79. saltLen++
  80. }
  81. salt := make([]byte, saltLen)
  82. rand.Read(salt)
  83. roundsText := ""
  84. if rounds != s.RoundsDefault {
  85. roundsText = "rounds=" + strconv.Itoa(rounds) + "$"
  86. }
  87. out := make([]byte, len(s.MagicPrefix)+len(roundsText)+length)
  88. copy(out, s.MagicPrefix)
  89. copy(out[len(s.MagicPrefix):], []byte(roundsText))
  90. copy(out[len(s.MagicPrefix)+len(roundsText):], Base64_24Bit(salt))
  91. return out
  92. }