OLD | NEW |
(Empty) | |
| 1 // Copyright 2011 The Go Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style |
| 3 // license that can be found in the LICENSE file. |
| 4 |
| 5 package bcrypt |
| 6 |
| 7 import ( |
| 8 "bytes" |
| 9 "os" |
| 10 "testing" |
| 11 ) |
| 12 |
| 13 func TestBcryptingIsEasy(t *testing.T) { |
| 14 pass := []byte("mypassword") |
| 15 hp, err := GenerateFromPassword(pass, 0) |
| 16 if err != nil { |
| 17 t.Fatalf("GenerateFromPassword error: %s", err) |
| 18 } |
| 19 |
| 20 if CompareHashAndPassword(hp, pass) != nil { |
| 21 t.Errorf("%v should hash %s correctly", hp, pass) |
| 22 } |
| 23 |
| 24 notPass := "notthepass" |
| 25 err = CompareHashAndPassword(hp, []byte(notPass)) |
| 26 if err != MismatchedHashAndPasswordError { |
| 27 t.Errorf("%v and %s should be mismatched", hp, notPass) |
| 28 } |
| 29 } |
| 30 |
| 31 func TestBcryptingIsCorrect(t *testing.T) { |
| 32 pass := []byte("allmine") |
| 33 salt := []byte("XajjQvNhvvRt5GSeFk1xFe") |
| 34 expectedHash := []byte("$2a$10$XajjQvNhvvRt5GSeFk1xFeyqRrsxkhBkUiQeg0dt.
wU1qD4aFDcga") |
| 35 |
| 36 hash, err := bcrypt(pass, 10, salt) |
| 37 if err != nil { |
| 38 t.Fatalf("bcrypt blew up: %v", err) |
| 39 } |
| 40 if !bytes.HasSuffix(expectedHash, hash) { |
| 41 t.Errorf("%v should be the suffix of %v", hash, expectedHash) |
| 42 } |
| 43 |
| 44 h, err := newFromHash(expectedHash) |
| 45 if err != nil { |
| 46 t.Errorf("Unable to parse %s: %v", string(expectedHash), err) |
| 47 } |
| 48 |
| 49 // This is not the safe way to compare these hashes. We do this only for |
| 50 // testing clarity. Use bcrypt.CompareHashAndPassword() |
| 51 if err == nil && !bytes.Equal(expectedHash, h.Hash()) { |
| 52 t.Errorf("Parsed hash %v should equal %v", h.Hash(), expectedHas
h) |
| 53 } |
| 54 } |
| 55 |
| 56 func TestTooLongPasswordsWork(t *testing.T) { |
| 57 salt := []byte("XajjQvNhvvRt5GSeFk1xFe") |
| 58 // One byte over the usual 56 byte limit that blowfish has |
| 59 tooLongPass := []byte("0123456789012345678901234567890123456789012345678
90123456") |
| 60 tooLongExpected := []byte("$2a$10$XajjQvNhvvRt5GSeFk1xFe5l47dONXg781AmZt
d869sO8zfsHuw7C") |
| 61 hash, err := bcrypt(tooLongPass, 10, salt) |
| 62 if err != nil { |
| 63 t.Fatalf("bcrypt blew up on long password: %v", err) |
| 64 } |
| 65 if !bytes.HasSuffix(tooLongExpected, hash) { |
| 66 t.Errorf("%v should be the suffix of %v", hash, tooLongExpected) |
| 67 } |
| 68 } |
| 69 |
| 70 type InvalidHashTest struct { |
| 71 err os.Error |
| 72 hash []byte |
| 73 } |
| 74 |
| 75 var invalidTests = []InvalidHashTest{ |
| 76 {HashTooShortError, []byte("$2a$10$fooo")}, |
| 77 {HashTooShortError, []byte("$2a")}, |
| 78 {HashVersionTooNewError('3'), []byte("$3a$10$sssssssssssssssssssssshhhhh
hhhhhhhhhhhhhhhhhhhhhhhhhh")}, |
| 79 {InvalidHashPrefixError('%'), []byte("%2a$10$sssssssssssssssssssssshhhhh
hhhhhhhhhhhhhhhhhhhhhhhhhh")}, |
| 80 {InvalidCostError(32), []byte("$2a$32$sssssssssssssssssssssshhhhhhhhhhhh
hhhhhhhhhhhhhhhhhhh")}, |
| 81 } |
| 82 |
| 83 func TestInvalidHashErrors(t *testing.T) { |
| 84 check := func(name string, expected, err os.Error) { |
| 85 if err == nil { |
| 86 t.Errorf("%s: Should have returned an error", name) |
| 87 } |
| 88 if err != nil && err != expected { |
| 89 t.Errorf("%s gave err %v but should have given %v", name
, err.String(), expected.String()) |
| 90 } |
| 91 } |
| 92 for _, iht := range invalidTests { |
| 93 _, err := newFromHash(iht.hash) |
| 94 check("newFromHash", iht.err, err) |
| 95 err = CompareHashAndPassword(iht.hash, []byte("anything")) |
| 96 check("CompareHashAndPassword", iht.err, err) |
| 97 } |
| 98 } |
| 99 |
| 100 func TestUnpaddedBase64EncodingWorks(t *testing.T) { |
| 101 original := []byte{101, 201, 101, 75, 19, 227, 199, 20, 239, 236, 133, 3
2, 30, 109, 243, 30} |
| 102 encodedOriginal := []byte("XajjQvNhvvRt5GSeFk1xFe") |
| 103 |
| 104 encoded := base64Encode(original) |
| 105 |
| 106 if !bytes.Equal(encodedOriginal, encoded) { |
| 107 t.Errorf("Encoded %v should have equaled %v", encoded, encodedOr
iginal) |
| 108 } |
| 109 |
| 110 decoded, err := base64Decode(encodedOriginal) |
| 111 if err != nil { |
| 112 t.Fatalf("base64Decode blew up: %s", err) |
| 113 } |
| 114 |
| 115 if !bytes.Equal(decoded, original) { |
| 116 t.Errorf("Decoded %v should have equaled %v", decoded, original) |
| 117 } |
| 118 } |
| 119 |
| 120 func TestCost(t *testing.T) { |
| 121 pass := []byte("mypassword") |
| 122 |
| 123 for c := 0; c < MinCost; c++ { |
| 124 p, _ := newFromPassword(pass, c) |
| 125 if p.cost != uint32(DefaultCost) { |
| 126 t.Errorf("newFromPassword should default costs below %d
to %d, but was %d", MinCost, DefaultCost, p.cost) |
| 127 } |
| 128 } |
| 129 |
| 130 p, _ := newFromPassword(pass, 14) |
| 131 if p.cost != 14 { |
| 132 t.Errorf("newFromPassword should default cost to 14, but was %d"
, p.cost) |
| 133 } |
| 134 |
| 135 hp, _ := newFromHash(p.Hash()) |
| 136 if p.cost != hp.cost { |
| 137 t.Errorf("newFromHash should maintain the cost at %d, but was %d
", p.cost, hp.cost) |
| 138 } |
| 139 |
| 140 _, err := newFromPassword(pass, 32) |
| 141 if err == nil { |
| 142 t.Fatalf("newFromPassword: should return a cost error") |
| 143 } |
| 144 if err != InvalidCostError(32) { |
| 145 t.Errorf("newFromPassword: should return cost error, got %#v", e
rr) |
| 146 } |
| 147 } |
| 148 |
| 149 func TestCostReturnsWithLeadingZeroes(t *testing.T) { |
| 150 hp, _ := newFromPassword([]byte("abcdefgh"), 7) |
| 151 cost := hp.Hash()[4:7] |
| 152 expected := []byte("07$") |
| 153 |
| 154 if !bytes.Equal(expected, cost) { |
| 155 t.Errorf("single digit costs in hash should have leading zeros:
was %v instead of %v", cost, expected) |
| 156 } |
| 157 } |
| 158 |
| 159 func TestMinorNotRequired(t *testing.T) { |
| 160 noMinorHash := []byte("$2$10$XajjQvNhvvRt5GSeFk1xFeyqRrsxkhBkUiQeg0dt.wU
1qD4aFDcga") |
| 161 h, err := newFromHash(noMinorHash) |
| 162 if err != nil { |
| 163 t.Fatalf("No minor hash blew up: %s", err) |
| 164 } |
| 165 if h.minor != 0 { |
| 166 t.Errorf("Should leave minor version at 0, but was %d", h.minor) |
| 167 } |
| 168 |
| 169 if !bytes.Equal(noMinorHash, h.Hash()) { |
| 170 t.Errorf("Should generate hash %v, but created %v", noMinorHash,
h.Hash()) |
| 171 } |
| 172 } |
| 173 |
| 174 func BenchmarkEqual(b *testing.B) { |
| 175 b.StopTimer() |
| 176 passwd := []byte("somepasswordyoulike") |
| 177 hash, _ := GenerateFromPassword(passwd, 10) |
| 178 b.StartTimer() |
| 179 for i := 0; i < b.N; i++ { |
| 180 CompareHashAndPassword(hash, passwd) |
| 181 } |
| 182 } |
| 183 |
| 184 func BenchmarkGeneration(b *testing.B) { |
| 185 b.StopTimer() |
| 186 passwd := []byte("mylongpassword1234") |
| 187 b.StartTimer() |
| 188 for i := 0; i < b.N; i++ { |
| 189 GenerateFromPassword(passwd, 10) |
| 190 } |
| 191 } |
OLD | NEW |