|
5 | 5 | _ "crypto/sha512" |
6 | 6 | "testing" |
7 | 7 |
|
8 | | - "golang.org/x/crypto/bcrypt" |
9 | | - |
10 | 8 | "github.com/dhui/passhash" |
11 | 9 | ) |
12 | 10 |
|
@@ -284,72 +282,68 @@ func TestMatchesPasswordUpdateWorkFactor(t *testing.T) { |
284 | 282 | } |
285 | 283 | } |
286 | 284 |
|
287 | | -func TestScryptWorkFactorMutationDoesNotBreakExistingCredential(t *testing.T) { |
288 | | - cfg := passhash.Config{ |
289 | | - Kdf: passhash.Scrypt, |
290 | | - WorkFactor: &passhash.ScryptWorkFactor{N: 1024, R: 16, P: 1}, |
291 | | - SaltSize: 16, |
292 | | - KeyLength: 32, |
293 | | - AuditLogger: &passhash.DummyAuditLogger{}, |
294 | | - Store: passhash.DummyCredentialStore{}, |
295 | | - } |
296 | | - userID := passhash.UserID(1) |
297 | | - |
298 | | - cred, err := cfg.NewCredential(userID, testPassword) |
299 | | - if err != nil { |
300 | | - t.Fatalf("Unable to create new Credential: %v", err) |
301 | | - } |
302 | | - |
303 | | - if matched, _ := cred.MatchesPasswordWithConfig(cfg, testPassword); !matched { |
304 | | - t.Fatalf("Password did not match before work factor change") |
305 | | - } |
306 | | - |
307 | | - wf := cfg.WorkFactor.(*passhash.ScryptWorkFactor) |
308 | | - wf.N *= 2 |
309 | | - |
310 | | - if matched, _ := cred.MatchesPasswordWithConfig(cfg, testPassword); !matched { |
311 | | - t.Fatalf("Password did not match after work factor change; credential should be stable") |
312 | | - } |
| 285 | +var configWorkFactorChangeDoesNotBreakExistingCredentialTests = map[string]struct { |
| 286 | + kdf passhash.Kdf |
| 287 | + wf passhash.WorkFactor |
| 288 | + wfMutator func(passhash.WorkFactor) |
| 289 | +}{ |
| 290 | + "pbkdf2 WorkFactor": { |
| 291 | + kdf: passhash.Pbkdf2Sha256, |
| 292 | + wf: &passhash.Pbkdf2WorkFactor{Iter: 10}, |
| 293 | + wfMutator: func(wf passhash.WorkFactor) { |
| 294 | + wf.(*passhash.Pbkdf2WorkFactor).Iter -= 1 |
| 295 | + }, |
| 296 | + }, |
| 297 | + "bcrypt WorkFactor": { |
| 298 | + kdf: passhash.Bcrypt, |
| 299 | + wf: &passhash.BcryptWorkFactor{Cost: 3}, |
| 300 | + wfMutator: func(wf passhash.WorkFactor) { |
| 301 | + wf.(*passhash.BcryptWorkFactor).Cost -= 1 |
| 302 | + }, |
| 303 | + }, |
| 304 | + "scrypt WorkFactor": { |
| 305 | + kdf: passhash.Scrypt, |
| 306 | + wf: &passhash.ScryptWorkFactor{N: 16, R: 16, P: 1}, |
| 307 | + wfMutator: func(wf passhash.WorkFactor) { |
| 308 | + wf.(*passhash.ScryptWorkFactor).N /= 2 |
| 309 | + }, |
| 310 | + }, |
313 | 311 | } |
314 | 312 |
|
315 | | -func TestBcryptWorkFactorMutationTriggersUpgrade(t *testing.T) { |
316 | | - cfg := passhash.Config{ |
317 | | - Kdf: passhash.Bcrypt, |
318 | | - WorkFactor: &passhash.BcryptWorkFactor{Cost: 10}, |
319 | | - SaltSize: 16, |
320 | | - KeyLength: 32, |
321 | | - AuditLogger: &passhash.DummyAuditLogger{}, |
322 | | - Store: passhash.DummyCredentialStore{}, |
323 | | - } |
324 | | - userID := passhash.UserID(2) |
325 | | - |
326 | | - cred, err := cfg.NewCredential(userID, testPassword) |
327 | | - if err != nil { |
328 | | - t.Fatalf("Unable to create new Credential: %v", err) |
329 | | - } |
330 | | - |
331 | | - beforeCost, err := bcrypt.Cost(cred.Hash) |
332 | | - if err != nil { |
333 | | - t.Fatalf("Unable to read bcrypt cost: %v", err) |
334 | | - } |
335 | | - |
336 | | - wf := cfg.WorkFactor.(*passhash.BcryptWorkFactor) |
337 | | - wf.Cost = beforeCost + 2 |
338 | | - |
339 | | - matched, updated := cred.MatchesPasswordWithConfig(cfg, testPassword) |
340 | | - if !matched { |
341 | | - t.Fatalf("Password did not match after bcrypt work factor change") |
342 | | - } |
343 | | - if !updated { |
344 | | - t.Fatalf("Expected credential to be upgraded after bcrypt work factor change") |
345 | | - } |
346 | | - |
347 | | - afterCost, err := bcrypt.Cost(cred.Hash) |
348 | | - if err != nil { |
349 | | - t.Fatalf("Unable to read bcrypt cost after upgrade: %v", err) |
350 | | - } |
351 | | - if afterCost <= beforeCost { |
352 | | - t.Fatalf("Expected bcrypt cost to increase, got before=%d after=%d", beforeCost, afterCost) |
| 313 | +func TestConfigWorkFactorChangeDoesNotBreakExistingCredential(t *testing.T) { |
| 314 | + for name, test := range configWorkFactorChangeDoesNotBreakExistingCredentialTests { |
| 315 | + t.Run(name, func(t *testing.T) { |
| 316 | + t.Parallel() |
| 317 | + |
| 318 | + cfg := passhash.Config{ |
| 319 | + Kdf: test.kdf, |
| 320 | + WorkFactor: test.wf, |
| 321 | + SaltSize: 16, |
| 322 | + KeyLength: 32, |
| 323 | + AuditLogger: &passhash.DummyAuditLogger{}, |
| 324 | + Store: passhash.DummyCredentialStore{}, |
| 325 | + } |
| 326 | + |
| 327 | + userID := passhash.UserID(1) |
| 328 | + cred, err := cfg.NewCredential(userID, testPassword) |
| 329 | + if err != nil { |
| 330 | + t.Fatalf("Unable to create new Credential: %v", err) |
| 331 | + } |
| 332 | + |
| 333 | + if matched, _ := cred.MatchesPasswordWithConfig(cfg, testPassword); !matched { |
| 334 | + t.Fatalf("Password did not match before work factor change") |
| 335 | + } |
| 336 | + |
| 337 | + test.wfMutator(test.wf) |
| 338 | + |
| 339 | + matched, updated := cred.MatchesPasswordWithConfig(cfg, testPassword) |
| 340 | + if !matched { |
| 341 | + t.Fatalf("Password did not match after work factor change") |
| 342 | + } |
| 343 | + if !updated { |
| 344 | + t.Fatalf("Expected credential to be upgraded after work factor change") |
| 345 | + } |
| 346 | + }) |
353 | 347 | } |
354 | 348 | } |
355 | 349 |
|
|
0 commit comments