// VerifyPassword checks if password is valid and upgrades it if its encrypting scheme was outdated // Returns isValid, wasUpdated, error func (a *Account) VerifyPassword(password string) (bool, bool, error) { isValid, err := mcf.Verify(password, a.Password) if err != nil { return false, false, err } if !isValid { return false, false, nil } isCurrent, err := mcf.IsCurrent(a.Password) if err != nil { return false, false, err } if !isCurrent { err := a.SetPassword(password) if err != nil { return true, false, err } a.Touch() return true, true, nil } return true, false, nil }
func TestVectors(t *testing.T) { for i, v := range testVectors { key, err := hex.DecodeString(v.key) if err != nil { t.Errorf("%d: could not decode key: %s: %s", i, v.key, err) continue } config, err := setConfig(len(key), v.iterations, len(v.salt)) if err != nil { t.Errorf("%d: unexpected error setting config: %s", i, err) } setSalt(v.salt) encoded, err := mcf.Create(v.plain) if err != nil { t.Errorf("%d: got unexpected error: %s", i, err) } passwd := password.New([]byte("pbkdf2")) err = passwd.Parse([]byte(encoded)) if err != nil { t.Errorf("%d: unexpected error creating password instance: %s", i, err) } if p, q := []byte(config.Params()), passwd.Params; !bytes.Equal(p, q) { t.Errorf("%d: params: expected %s, got %s", i, string(p), string(q)) } if p, q := []byte(v.salt), passwd.Salt; !bytes.Equal(p, q) { t.Errorf("%d: salt: expected %s, got %s", i, string(p), string(q)) } if p, q := key, passwd.Key; !bytes.Equal(p, q) { t.Errorf("%d: key: expected %x, got %x", i, p, q) } isValid, err := mcf.Verify(v.plain, encoded) if err != nil { t.Errorf("%d: verify: unexpected failure on %q: %s", i, encoded, err) continue } if !isValid { t.Errorf("%d: verify - unexpectedly returned false", i) continue } // perturb configuration... newConfig := *config newConfig.KeyLen += 1 for j, c := range []*Config{config, &newConfig} { setConfig(c.KeyLen, c.Iterations, c.SaltLen) isCurrent, err := mcf.IsCurrent(encoded) if err != nil { t.Errorf("%d-%d: IsCurrent: unexpected failure: %", i, j, err) continue } //old configuration says yes, new configuration says no if answer := c == config; isCurrent != answer { t.Errorf("%d-%d: IsCurrent: expecting %t got %t", i, j, answer, isCurrent) continue } } } }
func TestVectors(t *testing.T) { for i, v := range testVectors { x := strings.Split(v.salt[1:], "$") if len(x) != 3 { t.Fatalf("%d: invalid field structure: %s", i, v.salt) } costIn, saltIn := x[1], x[2] //index 0 is not interesting. salt, err := base64Decode([]byte(saltIn)) if err != nil { t.Fatalf("%d: error decoding salt: %s", i, err) } var cost int if _, err := fmt.Sscanf(costIn, "%02d", &cost); err != nil { t.Fatalf("%d: error decoding param [%+v]: %s", i, costIn, err) } // Hijack rand.Reader to feed salt to crypto/bcrypt. // Need extra salt because SetCost generates a digest // to test the new cost, and each of the 3 calls to it uses // up one portion of salt. rand.Reader = bytes.NewReader(bytes.Repeat(salt, 4)) err = SetCost(cost) if err != nil { t.Errorf("%d: SetCost: unexpected error: %s", i, err) } encoded, err := mcf.Create(v.plain) if err != nil { // password must be at least 2 bytes otherwise crypto/blowfish complains. // This really should be handled in crypto/bcrypt if len(v.plain) < 3 { continue } t.Errorf("%d: unexpected error: %s", i, err) continue } if want, got := v.passwd, encoded; want != got { t.Errorf("%d: output mismatch. want: %s, got %s", i, want, got) continue } isValid, err := mcf.Verify(v.plain, encoded) if err != nil { t.Errorf("%d: verify: unexpected failure on %q: %s", i, encoded, err) continue } if !isValid { t.Errorf("%d: IsValid: expecting true got false", i) continue } for j, pair := range []struct { cost int answer bool }{{cost, true}, {cost + 1, false}} { err := SetCost(pair.cost) if err != nil { t.Errorf("%d-%d: SetCost: unexpected error: %s", i, j, err) } isCurrent, err := mcf.IsCurrent(encoded) if err != nil { t.Errorf("%d-%d: IsCurrent: unexpected failure: %", i, j, err) continue } if isCurrent != pair.answer { t.Errorf("%d-%d: IsCurrent: expecting %t got %t", i, j, pair.answer, isCurrent) continue } } } }