Skip to content

Commit 7c2f361

Browse files
committed
feat(bcrypt): add cost implementation for bcrypt
1 parent 989da45 commit 7c2f361

3 files changed

Lines changed: 76 additions & 4 deletions

File tree

crypto.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,15 @@ func adler32sum(input string) string {
5757
return fmt.Sprintf("%d", hash)
5858
}
5959

60-
func bcrypt(input string) string {
61-
hash, err := bcrypt_lib.GenerateFromPassword([]byte(input), bcrypt_lib.DefaultCost)
60+
func bcrypt(input string, cost ...int) string {
61+
c := bcrypt_lib.DefaultCost
62+
if len(cost) > 0 {
63+
c = cost[0]
64+
}
65+
if len(cost) > 1 {
66+
return fmt.Sprintf("multiple cost parameter set: %v", cost)
67+
}
68+
hash, err := bcrypt_lib.GenerateFromPassword([]byte(input), c)
6269
if err != nil {
6370
return fmt.Sprintf("failed to encrypt string with bcrypt: %s", err)
6471
}

crypto_test.go

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/base64"
66
"encoding/pem"
77
"fmt"
8+
"strconv"
89
"strings"
910
"testing"
1011

@@ -54,16 +55,80 @@ func TestAdler32Sum(t *testing.T) {
5455
}
5556
}
5657

57-
func TestBcrypt(t *testing.T) {
58+
func TestBcryptDefaultCost(t *testing.T) {
5859
out, err := runRaw(`{{"abc" | bcrypt}}`, nil)
5960
if err != nil {
6061
t.Error(err)
6162
}
63+
result := strings.Split(out, "$")
64+
passwordCost, err := strconv.Atoi(result[2])
65+
if err != nil {
66+
t.Error(err)
67+
}
68+
if passwordCost != bcrypt_lib.DefaultCost {
69+
t.Error("Generated hash has not the expected cost. Got:", passwordCost, " Expected:", bcrypt_lib.DefaultCost)
70+
}
71+
if bcrypt_lib.CompareHashAndPassword([]byte(out), []byte("abc")) != nil {
72+
t.Error("Generated hash is not the equivalent for password:", "abc")
73+
}
74+
}
75+
76+
func TestBcryptCustomCost(t *testing.T) { // 4 >= validCost <= 31
77+
out, err := runRaw(`{{bcrypt "abc" 12 }}`, nil)
78+
if err != nil {
79+
t.Error(err)
80+
}
81+
result := strings.Split(out, "$")
82+
passwordCost, err := strconv.Atoi(result[2])
83+
if err != nil {
84+
t.Error(err)
85+
}
86+
if passwordCost != 12 {
87+
t.Error("Generated hash has not the expected cost. got:", passwordCost, "expected:", 12)
88+
}
89+
if bcrypt_lib.CompareHashAndPassword([]byte(out), []byte("abc")) != nil {
90+
t.Error("Generated hash is not the equivalent for password:", "abc")
91+
}
92+
}
93+
94+
func TestBcryptMinCost(t *testing.T) {
95+
out, err := runRaw(`{{bcrypt "abc" 3 }}`, nil)
96+
if err != nil {
97+
t.Error(err)
98+
}
99+
result := strings.Split(out, "$")
100+
passwordCost, err := strconv.Atoi(result[2])
101+
if err != nil {
102+
t.Error(err)
103+
}
104+
if passwordCost != bcrypt_lib.DefaultCost {
105+
t.Error("Generated hash has not the expected cost. got:", passwordCost, "expected:", bcrypt_lib.DefaultCost)
106+
}
62107
if bcrypt_lib.CompareHashAndPassword([]byte(out), []byte("abc")) != nil {
63108
t.Error("Generated hash is not the equivalent for password:", "abc")
64109
}
65110
}
66111

112+
func TestBcryptMaxCost(t *testing.T) {
113+
out, err := runRaw(`{{bcrypt "abc" 32 }}`, nil)
114+
if err != nil {
115+
t.Error(err)
116+
}
117+
if !strings.HasPrefix(out, "failed to encrypt string with bcrypt") {
118+
t.Error("Generated string should be a failure message, got:", out, "expected: failed to encrypt string with bcrypt")
119+
}
120+
}
121+
122+
func TestBcryptMultipleCostParameter(t *testing.T) {
123+
out, err := runRaw(`{{bcrypt "abc" 10 10 }}`, nil)
124+
if err != nil {
125+
t.Error(err)
126+
}
127+
if !strings.HasPrefix(out, "multiple cost parameter set") {
128+
t.Error("Generated string should be a failure message, got:", out, "expected: multiple cost parameter set")
129+
}
130+
}
131+
67132
type HtpasswdCred struct {
68133
Username string
69134
Password string

docs/crypto.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ adler32sum "Hello world!"
4141
```
4242
## bcrypt
4343

44-
The `bcrypt` function receives a string, and generates its `bcrypt` hash.
44+
The `bcrypt` function takes a `input`, and a `cost` and generates a `bcrypt` hash. `cost` is optional and defaults to `bcrypt_lib.DefaultCost` (10).
4545

4646
```
4747
bcrypt "myPassword"

0 commit comments

Comments
 (0)