Esempio n. 1
0
// Key derives a key from the password, salt, and cost parameters, returning
// a byte slice of length keyLen that can be used as cryptographic key.
//
// N is a CPU/memory cost parameter, which must be a power of two greater than 1.
// r and p must satisfy r * p < 2³⁰. If the parameters do not satisfy the
// limits, the function returns a nil byte slice and an error.
//
// For example, you can get a derived key for e.g. AES-256 (which needs a
// 32-byte key) by doing:
//
//      dk := scrypt.Key([]byte("some password"), salt, 16384, 8, 1, 32)
//
// The recommended parameters for interactive logins as of 2009 are N=16384,
// r=8, p=1. They should be increased as memory latency and CPU parallelism
// increases. Remember to get a good random salt.
func Key(password, salt []byte, N, r, p, keyLen int) ([]byte, error) {
	if N <= 1 || N&(N-1) != 0 {
		return nil, errors.New("scrypt: N must be > 1 and a power of 2")
	}
	if uint64(r)*uint64(p) >= 1<<30 || r > maxInt/128/p || r > maxInt/256 || N > maxInt/128/r {
		return nil, errors.New("scrypt: parameters are too large")
	}

	xy := make([]uint32, 64*r)
	v := make([]uint32, 32*N*r)
	b := pbkdf2.Key(password, salt, 1, p*128*r, sha256.New)

	for i := 0; i < p; i++ {
		smix(b[i*128*r:], r, N, v, xy)
	}

	return pbkdf2.Key(password, b, 1, keyLen, sha256.New), nil
}
Esempio n. 2
0
// Save the key for the given secret of the given user in the named auth domain
// at KeyFile(dir, name).
// The key is added if there is no such user in the auth domain or replaced
// if the user already exists.
func SaveKey(dir, name, user, secret string, groups ...string) error {
	if dir == "" {
		dir = KeyDir()
	}
	if name == "" {
		name = "default"
	}
	file := KeyFile(dir, name)
	data := []byte(secret)
	key := pbkdf2.Key(data, []byte("ltsa"), 1000, 32, sha1.New)

	old, _ := LoadKey(dir, name)
	new := []Key{}
	for _, o := range old {
		if o.Uid != user {
			new = append(new, o)
		}
	}
	new = append(new, Key{Uid: user, Gids: groups, Key: key})
	fd, err := os.Create(file)
	if err != nil {
		return err
	}
	for _, k := range new {
		if _, err := fmt.Fprintf(fd, "%s", k.Uid); err != nil {
			os.Remove(file)
			return err
		}
		for _, g := range k.Gids {
			if _, err := fmt.Fprintf(fd, " %s", g); err != nil {
				os.Remove(file)
				return err
			}
		}
		if _, err := fmt.Fprintf(fd, "\n%x\n", k.Key); err != nil {
			os.Remove(file)
			return err
		}
	}
	if err := fd.Close(); err != nil {
		os.Remove(file)
		return err
	}
	if err := os.Chmod(file, 0600); err != nil {
		os.Remove(file)
		return err
	}
	return nil
}