-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpasslock_test.go
161 lines (133 loc) · 4.11 KB
/
passlock_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package passlock
import (
"crypto/rand"
"fmt"
"io"
"strconv"
"strings"
"testing"
)
func Example() {
// Your plaintext password
password := []byte("password")
// Get a key
key := NewEncryptionKey()
// Store the password
encryptedPassword, err := GenerateFromPassword(password, DefaultCost, key)
if err != nil {
fmt.Println(err)
}
// Retrieve the password
err = CompareHashAndPassword(encryptedPassword, password, key)
if err != nil {
fmt.Println(err)
return
}
// We're going to rotate keys -- let's start by making a new key
newKey := NewEncryptionKey()
// Rotate the keys
newEncryptedPassword, err := RotateKey(key, newKey, encryptedPassword)
if err != nil {
fmt.Println(err)
return
}
// See if that password matches with the new key
err = CompareHashAndPassword(newEncryptedPassword, password, newKey)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("Passwords matched!")
// Output: Passwords matched!
}
func TestNewEncryptionKey(t *testing.T) {
t.Parallel()
keyA := NewEncryptionKey()
keyB := NewEncryptionKey()
if keyA == keyB {
t.Fatalf("Key %s should not equal %s\n", keyA, keyB)
}
if len(keyA) != 32 {
t.Fatalf("Keys should be 32 bytes long, KeyA is %d bytes\n", len(keyA))
}
}
func TestGenerateFromPassword_LongPassword(t *testing.T) {
t.Parallel()
key := NewEncryptionKey()
longPassword := make([]byte, 128)
_, err := io.ReadFull(rand.Reader, longPassword)
if err != nil {
t.Fatalf("Unexpected error reading from rand.Reader: %#v\n", err)
}
// Test that you can use 128 byte long password
encryptedPassword, err := GenerateFromPassword(longPassword, DefaultCost, key)
if err != nil {
t.Fatalf("Unexpected error generating password: %#v\n", err)
}
err = CompareHashAndPassword(encryptedPassword, longPassword, key)
if err != nil {
t.Fatalf("Long passwords do not match: %#v\n", err)
}
err = CompareHashAndPassword(encryptedPassword, longPassword[:100], key)
if err == nil {
t.Fatalf("CompareHashAndPassword returned no error for mismatched long passwords:\n%s\nvs\n%s\n", longPassword, longPassword[:100])
}
}
func TestGenerateFromPassword_DefaultCost(t *testing.T) {
t.Parallel()
key := NewEncryptionKey()
password := []byte("password")
// Test that work factor is at least the default cost, even if a smaller
// value is passsed.
encryptedPassword, err := GenerateFromPassword(password, 10, key)
if err != nil {
t.Fatalf("Unexpected error: %#v\n", err)
}
plainPassword, err := decrypt(encryptedPassword, key)
if err != nil {
t.Fatalf("Unexpected error: %#v\n", err)
}
if !strings.Contains(string(plainPassword), "$"+strconv.Itoa(DefaultCost)) {
t.Fatalf("Password was hashed with a work factor lower than %d\n", DefaultCost)
}
}
// Check stupid null character even though Go's bcrypt implementation protects
// against it.
func TestGenerateFromPassword_NulByte(t *testing.T) {
t.Parallel()
key := NewEncryptionKey()
nullPasswordA := "abc/0123"
nullPasswordB := "abc/0456"
// Golang's bcrypt implementation already protects against this, but we'll
// test it anyway as a sanity check.
encryptedPassword, err := GenerateFromPassword([]byte(nullPasswordA), DefaultCost, key)
if err != nil {
t.Fatalf("Unexpected error: %#v\n", err)
}
err = CompareHashAndPassword(encryptedPassword, []byte(nullPasswordB), key)
if err == nil {
t.Fatalf("Passwords %s and %s are not the same, but appear to match\n", nullPasswordA, nullPasswordB)
}
}
func TestRotateKey(t *testing.T) {
t.Parallel()
keyA := NewEncryptionKey()
keyB := NewEncryptionKey()
password := []byte("password")
encryptedPassword, err := GenerateFromPassword(password, DefaultCost, keyA)
if err != nil {
t.Fatalf("Unexpected error hashing password: %#v\n", err)
}
newEncryptedPassword, err := RotateKey(keyA, keyB, encryptedPassword)
if err != nil {
t.Fatalf("Unexpected error rotating key: %#v\n", err)
}
err = CompareHashAndPassword(newEncryptedPassword, password, keyB)
if err != nil {
t.Fatalf("Expected password to match but got %#v\n", err)
}
err = CompareHashAndPassword(newEncryptedPassword, password, keyA)
if err == nil {
t.Fatalf("Expected decryption to fail.\n")
}
}