-
Notifications
You must be signed in to change notification settings - Fork 3
/
decoder.go
189 lines (152 loc) · 6.26 KB
/
decoder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
package crypt
import (
"fmt"
"strconv"
"strings"
"github.com/go-crypt/crypt/algorithm"
"github.com/go-crypt/crypt/algorithm/argon2"
"github.com/go-crypt/crypt/algorithm/bcrypt"
"github.com/go-crypt/crypt/algorithm/md5crypt"
"github.com/go-crypt/crypt/algorithm/pbkdf2"
"github.com/go-crypt/crypt/algorithm/plaintext"
"github.com/go-crypt/crypt/algorithm/scrypt"
"github.com/go-crypt/crypt/algorithm/sha1crypt"
"github.com/go-crypt/crypt/algorithm/shacrypt"
"github.com/go-crypt/crypt/internal/encoding"
)
// NewDecoder returns a new empty *Decoder.
//
// See Also: NewDefaultDecoder and NewDecoderAll.
func NewDecoder() *Decoder {
return &Decoder{
decoders: map[string]algorithm.DecodeFunc{},
prefixes: map[string]string{},
}
}
// NewDefaultDecoder returns the default decoder recommended for new implementations.
//
// Loaded Decoders: argon2, bcrypt, pbkdf2, scrypt, shacrypt.
//
// CRITICAL STABILITY NOTE: the decoders loaded via this function are not guaranteed to remain the same. It is strongly
// recommended that users implementing this library use this or NewDecodersAll only as an example for building their own
// decoder via NewDecoder instead which returns an empty decoder. It is much safer for security and stability to be
// explicit in harmony with your specific use case. It is the responsibility of the implementer to determine which
// password algorithms are sufficiently safe for their particular use case.
func NewDefaultDecoder() (d *Decoder, err error) {
d = &Decoder{
decoders: map[string]algorithm.DecodeFunc{},
prefixes: map[string]string{},
}
if err = decoderProfileDefault(d); err != nil {
return nil, err
}
return d, nil
}
// NewDecoderAll is the same as NewDefaultDecoder but it also adds legacy and/or insecure decoders.
//
// Loaded Decoders (in addition to NewDefaultDecoder): plaintext, md5crypt, sha1crypt.
//
// CRITICAL STABILITY NOTE: the decoders loaded via this function are not guaranteed to remain the same. It is strongly
// recommended that users implementing this library use this or NewDecodersAll only as an example for building their own
// decoder via NewDecoder instead which returns an empty decoder. It is much safer for security and stability to be
// explicit in harmony with your specific use case. It is the responsibility of the implementer to determine which
// password algorithms are sufficiently safe for their particular use case.
func NewDecoderAll() (d *Decoder, err error) {
d = &Decoder{
decoders: map[string]algorithm.DecodeFunc{},
prefixes: map[string]string{},
}
if err = decoderProfileDefault(d); err != nil {
return nil, err
}
if err = plaintext.RegisterDecoder(d); err != nil {
return nil, fmt.Errorf("could not register the plaintext decoder: %w", err)
}
if err = md5crypt.RegisterDecoder(d); err != nil {
return nil, fmt.Errorf("could not register the md5crypt decoder: %w", err)
}
if err = sha1crypt.RegisterDecoder(d); err != nil {
return nil, fmt.Errorf("could not register the sha1crypt decoder: %w", err)
}
return d, nil
}
// Decoder is a struct which allows registering algorithm.DecodeFunc's and utilizing the programmatically to decode an
// encoded digest with them.
type Decoder struct {
decoders map[string]algorithm.DecodeFunc
prefixes map[string]string
}
// RegisterDecodeFunc registers a new algorithm.DecodeFunc with this Decoder against a specific identifier.
func (d *Decoder) RegisterDecodeFunc(identifier string, decoder algorithm.DecodeFunc) (err error) {
if d.decoders == nil {
d.decoders = map[string]algorithm.DecodeFunc{}
}
if _, ok := d.decoders[identifier]; ok {
return fmt.Errorf("decoder already registered for identifier '%s'", identifier)
}
d.decoders[identifier] = decoder
return nil
}
// RegisterDecodePrefix registers a prefix which is matched by strings.HasPrefix.
func (d *Decoder) RegisterDecodePrefix(prefix, identifier string) (err error) {
if d.decoders == nil {
return fmt.Errorf("no decoders are registered")
}
if d.prefixes == nil {
d.prefixes = map[string]string{}
}
if _, ok := d.decoders[identifier]; !ok {
return fmt.Errorf("decoder isn't registered for dentifier '%s'", identifier)
}
d.prefixes[prefix] = identifier
return nil
}
// Decode an encoded digest into a algorithm.Digest.
func (d *Decoder) Decode(encodedDigest string) (digest algorithm.Digest, err error) {
if digest, err = d.decode(encodedDigest); err != nil {
return nil, err
}
return digest, nil
}
func (d *Decoder) decode(encodedDigest string) (digest algorithm.Digest, err error) {
for prefix, key := range d.prefixes {
if strings.HasPrefix(encodedDigest, prefix) {
return d.decoders[key](encodedDigest)
}
}
encodedDigest = Normalize(encodedDigest)
if len(encodedDigest) == 0 || rune(encodedDigest[0]) != encoding.Delimiter {
return nil, fmt.Errorf("%w: the digest doesn't begin with the delimiter %s and is not one of the other understood formats", algorithm.ErrEncodedHashInvalidFormat, strconv.QuoteRune(encoding.Delimiter))
}
parts := encoding.Split(encodedDigest, 3)
if len(parts) != 3 {
return nil, fmt.Errorf("%w: the digest doesn't have the minimum number of parts for it to be considered an encoded digest", algorithm.ErrEncodedHashInvalidFormat)
}
if decodeFunc, ok := d.decoders[parts[1]]; ok {
return decodeFunc(encodedDigest)
}
switch d {
case gdecoder:
return nil, fmt.Errorf("%w: the identifier '%s' is unknown to the global decoder", algorithm.ErrEncodedHashInvalidIdentifier, parts[1])
default:
return nil, fmt.Errorf("%w: the identifier '%s' is unknown to the decoder", algorithm.ErrEncodedHashInvalidIdentifier, parts[1])
}
}
func decoderProfileDefault(decoder *Decoder) (err error) {
if err = argon2.RegisterDecoder(decoder); err != nil {
return fmt.Errorf("could not register the argon2 decoder: %w", err)
}
if err = bcrypt.RegisterDecoder(decoder); err != nil {
return fmt.Errorf("could not register the bcrypt decoder: %w", err)
}
if err = pbkdf2.RegisterDecoder(decoder); err != nil {
return fmt.Errorf("could not register the pbkdf2 decoder: %w", err)
}
if err = scrypt.RegisterDecoder(decoder); err != nil {
return fmt.Errorf("could not register the scrypt decoder: %w", err)
}
if err = shacrypt.RegisterDecoder(decoder); err != nil {
return fmt.Errorf("could not register the shacrypt decoder: %w", err)
}
return nil
}