pass
pass/pass.go
Fix a bug with salt generation. Our salt generation had a logic bug that would bail out in the absence of an error and continue on in the presence of an error, which is exactly the opposite of the behaviour we want. Basically, typo.
| paddy@0 | 1 package pass |
| paddy@0 | 2 |
| paddy@0 | 3 import ( |
| paddy@0 | 4 "crypto/rand" |
| paddy@0 | 5 "crypto/subtle" |
| paddy@0 | 6 "hash" |
| paddy@0 | 7 "time" |
| paddy@0 | 8 |
| paddy@0 | 9 "code.google.com/p/go.crypto/pbkdf2" |
| paddy@0 | 10 ) |
| paddy@0 | 11 |
| paddy@0 | 12 func Create(h func() hash.Hash, iters int, passphrase []byte) (result, salt []byte, err error) { |
| paddy@0 | 13 salt = make([]byte, 32) |
| paddy@0 | 14 _, err = rand.Read(salt) |
| paddy@1 | 15 if err != nil { |
| paddy@0 | 16 return []byte{}, []byte{}, err |
| paddy@0 | 17 } |
| paddy@0 | 18 result = Check(h, iters, passphrase, salt) |
| paddy@0 | 19 return result, salt, err |
| paddy@0 | 20 } |
| paddy@0 | 21 |
| paddy@0 | 22 func CalculateIterations(h func() hash.Hash) (int, error) { |
| paddy@0 | 23 hashInstance := h() |
| paddy@0 | 24 salt := make([]byte, 32) |
| paddy@0 | 25 _, err := rand.Read(salt) |
| paddy@0 | 26 if err != nil { |
| paddy@0 | 27 return 0, err |
| paddy@0 | 28 } |
| paddy@0 | 29 iter := 2048 |
| paddy@0 | 30 var duration time.Duration |
| paddy@0 | 31 for duration < time.Second { |
| paddy@0 | 32 iter = iter * 2 |
| paddy@0 | 33 timeStart := time.Now() |
| paddy@0 | 34 pbkdf2.Key([]byte("password1"), salt, iter, hashInstance.Size(), h) |
| paddy@0 | 35 duration = time.Since(timeStart) |
| paddy@0 | 36 } |
| paddy@0 | 37 return iter, nil |
| paddy@0 | 38 } |
| paddy@0 | 39 |
| paddy@0 | 40 func Check(h func() hash.Hash, iters int, passphrase, salt []byte) []byte { |
| paddy@0 | 41 hashInstance := h() |
| paddy@0 | 42 return pbkdf2.Key(passphrase, salt, iters, hashInstance.Size(), h) |
| paddy@0 | 43 } |
| paddy@0 | 44 |
| paddy@0 | 45 func Compare(candidate, expectation []byte) bool { |
| paddy@0 | 46 candidateConsistent := make([]byte, len(candidate)) |
| paddy@0 | 47 expectationConsistent := make([]byte, len(candidate)) |
| paddy@0 | 48 subtle.ConstantTimeCopy(1, candidateConsistent, candidate) |
| paddy@0 | 49 subtle.ConstantTimeCopy(1, expectationConsistent, expectation) |
| paddy@0 | 50 return subtle.ConstantTimeCompare(candidateConsistent, expectationConsistent) == 1 |
| paddy@0 | 51 } |