...
1
2
3
4
5
6
7
8 package common
9
10 import (
11 "crypto/rand"
12 "errors"
13 "strconv"
14 )
15
16 var (
17 ErrSaltPrefix = errors.New("invalid magic prefix")
18 ErrSaltFormat = errors.New("invalid salt format")
19 ErrSaltRounds = errors.New("invalid rounds")
20 )
21
22
23 type Salt struct {
24 MagicPrefix []byte
25
26 SaltLenMin int
27 SaltLenMax int
28
29 RoundsMin int
30 RoundsMax int
31 RoundsDefault int
32 }
33
34 func (s *Salt) Generate(length int) []byte {
35 if length > s.SaltLenMax {
36 length = s.SaltLenMax
37 } else if length < s.SaltLenMin {
38 length = s.SaltLenMin
39 }
40
41 saltLen := (length * 6 / 8)
42 if (length*6)%8 != 0 {
43 saltLen++
44 }
45 salt := make([]byte, saltLen)
46 _, err := rand.Read(salt)
47 if err != nil {
48 return []byte{}
49 }
50
51 out := make([]byte, len(s.MagicPrefix)+length)
52 copy(out, s.MagicPrefix)
53 copy(out[len(s.MagicPrefix):], Base64_24Bit(salt))
54 return out
55 }
56
57 func (s *Salt) GenerateWRounds(length, rounds int) []byte {
58 if length > s.SaltLenMax {
59 length = s.SaltLenMax
60 } else if length < s.SaltLenMin {
61 length = s.SaltLenMin
62 }
63 if rounds < 0 {
64 rounds = s.RoundsDefault
65 } else if rounds < s.RoundsMin {
66 rounds = s.RoundsMin
67 } else if rounds > s.RoundsMax {
68 rounds = s.RoundsMax
69 }
70
71 saltLen := (length * 6 / 8)
72 if (length*6)%8 != 0 {
73 saltLen++
74 }
75 salt := make([]byte, saltLen)
76 _, err := rand.Read(salt)
77 if err != nil {
78 return []byte{}
79 }
80
81 roundsText := ""
82 if rounds != s.RoundsDefault {
83 roundsText = "rounds=" + strconv.Itoa(rounds) + "$"
84 }
85
86 out := make([]byte, len(s.MagicPrefix)+len(roundsText)+length)
87 copy(out, s.MagicPrefix)
88 copy(out[len(s.MagicPrefix):], []byte(roundsText))
89 copy(out[len(s.MagicPrefix)+len(roundsText):], Base64_24Bit(salt))
90 return out
91 }
92
View as plain text