1
2
3
4
5
6
7
8
9
10
11
12
13 package s2k
14
15 import (
16 "crypto"
17 "hash"
18 "io"
19 "strconv"
20
21 "golang.org/x/crypto/openpgp/errors"
22 )
23
24
25
26
27
28 type Config struct {
29
30
31 Hash crypto.Hash
32
33
34
35
36
37
38
39
40
41
42 S2KCount int
43 }
44
45 func (c *Config) hash() crypto.Hash {
46 if c == nil || uint(c.Hash) == 0 {
47
48 return crypto.SHA1
49 }
50
51 return c.Hash
52 }
53
54 func (c *Config) encodedCount() uint8 {
55 if c == nil || c.S2KCount == 0 {
56 return 96
57 }
58
59 i := c.S2KCount
60 switch {
61
62 case i < 1024:
63 i = 1024
64 case i > 65011712:
65 i = 65011712
66 }
67
68 return encodeCount(i)
69 }
70
71
72
73
74
75
76 func encodeCount(i int) uint8 {
77 if i < 1024 || i > 65011712 {
78 panic("count arg i outside the required range")
79 }
80
81 for encoded := 0; encoded < 256; encoded++ {
82 count := decodeCount(uint8(encoded))
83 if count >= i {
84 return uint8(encoded)
85 }
86 }
87
88 return 255
89 }
90
91
92
93 func decodeCount(c uint8) int {
94 return (16 + int(c&15)) << (uint32(c>>4) + 6)
95 }
96
97
98
99 func Simple(out []byte, h hash.Hash, in []byte) {
100 Salted(out, h, in, nil)
101 }
102
103 var zero [1]byte
104
105
106
107 func Salted(out []byte, h hash.Hash, in []byte, salt []byte) {
108 done := 0
109 var digest []byte
110
111 for i := 0; done < len(out); i++ {
112 h.Reset()
113 for j := 0; j < i; j++ {
114 h.Write(zero[:])
115 }
116 h.Write(salt)
117 h.Write(in)
118 digest = h.Sum(digest[:0])
119 n := copy(out[done:], digest)
120 done += n
121 }
122 }
123
124
125
126
127 func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) {
128 combined := make([]byte, len(in)+len(salt))
129 copy(combined, salt)
130 copy(combined[len(salt):], in)
131
132 if count < len(combined) {
133 count = len(combined)
134 }
135
136 done := 0
137 var digest []byte
138 for i := 0; done < len(out); i++ {
139 h.Reset()
140 for j := 0; j < i; j++ {
141 h.Write(zero[:])
142 }
143 written := 0
144 for written < count {
145 if written+len(combined) > count {
146 todo := count - written
147 h.Write(combined[:todo])
148 written = count
149 } else {
150 h.Write(combined)
151 written += len(combined)
152 }
153 }
154 digest = h.Sum(digest[:0])
155 n := copy(out[done:], digest)
156 done += n
157 }
158 }
159
160
161
162 func Parse(r io.Reader) (f func(out, in []byte), err error) {
163 var buf [9]byte
164
165 _, err = io.ReadFull(r, buf[:2])
166 if err != nil {
167 return
168 }
169
170 hash, ok := HashIdToHash(buf[1])
171 if !ok {
172 return nil, errors.UnsupportedError("hash for S2K function: " + strconv.Itoa(int(buf[1])))
173 }
174 if !hash.Available() {
175 return nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hash)))
176 }
177 h := hash.New()
178
179 switch buf[0] {
180 case 0:
181 f := func(out, in []byte) {
182 Simple(out, h, in)
183 }
184 return f, nil
185 case 1:
186 _, err = io.ReadFull(r, buf[:8])
187 if err != nil {
188 return
189 }
190 f := func(out, in []byte) {
191 Salted(out, h, in, buf[:8])
192 }
193 return f, nil
194 case 3:
195 _, err = io.ReadFull(r, buf[:9])
196 if err != nil {
197 return
198 }
199 count := decodeCount(buf[8])
200 f := func(out, in []byte) {
201 Iterated(out, h, in, buf[:8], count)
202 }
203 return f, nil
204 }
205
206 return nil, errors.UnsupportedError("S2K function")
207 }
208
209
210
211
212
213 func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte, c *Config) error {
214 var buf [11]byte
215 buf[0] = 3
216 buf[1], _ = HashToHashId(c.hash())
217 salt := buf[2:10]
218 if _, err := io.ReadFull(rand, salt); err != nil {
219 return err
220 }
221 encodedCount := c.encodedCount()
222 count := decodeCount(encodedCount)
223 buf[10] = encodedCount
224 if _, err := w.Write(buf[:]); err != nil {
225 return err
226 }
227
228 Iterated(key, c.hash().New(), passphrase, salt, count)
229 return nil
230 }
231
232
233
234 var hashToHashIdMapping = []struct {
235 id byte
236 hash crypto.Hash
237 name string
238 }{
239 {1, crypto.MD5, "MD5"},
240 {2, crypto.SHA1, "SHA1"},
241 {3, crypto.RIPEMD160, "RIPEMD160"},
242 {8, crypto.SHA256, "SHA256"},
243 {9, crypto.SHA384, "SHA384"},
244 {10, crypto.SHA512, "SHA512"},
245 {11, crypto.SHA224, "SHA224"},
246 }
247
248
249
250 func HashIdToHash(id byte) (h crypto.Hash, ok bool) {
251 for _, m := range hashToHashIdMapping {
252 if m.id == id {
253 return m.hash, true
254 }
255 }
256 return 0, false
257 }
258
259
260
261 func HashIdToString(id byte) (name string, ok bool) {
262 for _, m := range hashToHashIdMapping {
263 if m.id == id {
264 return m.name, true
265 }
266 }
267
268 return "", false
269 }
270
271
272 func HashToHashId(h crypto.Hash) (id byte, ok bool) {
273 for _, m := range hashToHashIdMapping {
274 if m.hash == h {
275 return m.id, true
276 }
277 }
278 return 0, false
279 }
280
View as plain text