bcrypt_test.go 5.4 KB

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