// IsCurrent returns true if the parameters used to generate the encoded password // are at least as good as those in params. // If IsCurrent returns false the encoding is out of date and should be regenerated, // the application should call mcf.Create() to produce a new encoding to replace the current one. func (enc *Encoder) IsCurrent(encoded []byte) (isCurrent bool, err error) { passwd := password.New(enc.name) err = passwd.Parse(encoded) if err != nil { return } imp := enc.implementer() err = imp.SetParams(string(passwd.Params)) if err != nil { return } return imp.AtLeast(enc.implementer()), nil }
func TestKey(t *testing.T) { for i, v := range good { err := setConfig(len(v.output), len(v.salt), v.N, v.r, v.p) if err != nil { t.Errorf("%d: unexpected error setting config: %s", i, err) } setSalt(v.salt) encoded, err := mcf.Create(v.password) if err != nil { t.Errorf("%d: got unexpected error: %s", i, err) } passwd := password.New([]byte("scrypt")) err = passwd.Parse([]byte(encoded)) if err != nil { t.Errorf("%d: unexpected error creating password instance: %s", err) } if !bytes.Equal(passwd.Salt, []byte(v.salt)) { t.Errorf("%d: salt: expected %s, got %s", i, v.salt, string(passwd.Salt)) } if !bytes.Equal(passwd.Key, v.output) { t.Errorf("%d: expected %x, got %x", i, v.output, passwd.Key) } } for i, v := range bad { err := setConfig(32, len(v.salt), v.N, v.r, v.p) if err == nil { t.Errorf("%d: expected error, got nil", i) } setSalt(v.salt) _, err = mcf.Create(v.password) if err == nil { t.Errorf("%d: expected error, got nil", i) } } }
// Create produces an encoded password from a plaintext password using the current configuration. // The application must store the encoded password for future use. func (enc *Encoder) Create(plaintext []byte) (encoded []byte, err error) { imp := enc.implementer() passwd := password.New(enc.name) passwd.Params = []byte(imp.Params()) passwd.Salt, err = imp.Salt() if err != nil { return } passwd.Key, err = imp.Key(plaintext, passwd.Salt) if err != nil { return } return passwd.Bytes(), nil }
// Verify returns true if the proffered plaintext password, // when encoded using the same parameters, matches the encoded password. func (enc *Encoder) Verify(plaintext, encoded []byte) (isValid bool, err error) { passwd := password.New(enc.name) err = passwd.Parse(encoded) if err != nil { return } imp := enc.implementer() err = imp.SetParams(string(passwd.Params)) if err != nil { return } testKey, err := imp.Key(plaintext, passwd.Salt) if err != nil { return } return subtle.ConstantTimeCompare(passwd.Key, testKey) == 1, 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 } } } }