storj/pkg/encryption/password.go
Jeff Wendling 81f1bc19dc add functions for password/root key derivation (#2294)
This commit adds two functions that implement the algorithms
described in the password key derivation design document. They
will be used during setup to derive bucket level root keys or
default passwords to use when buckets do not have their own
independent key.

Change-Id: Ie7fb2d8d549ba7465d0722716a2c1ac0ad907286
2019-06-21 18:21:16 -04:00

62 lines
1.7 KiB
Go

// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package encryption
import (
"crypto/hmac"
"crypto/sha256"
"runtime"
"github.com/zeebo/errs"
"golang.org/x/crypto/argon2"
"storj.io/storj/pkg/storj"
)
func sha256hmac(key, data []byte) ([]byte, error) {
h := hmac.New(sha256.New, key)
if _, err := h.Write(data); err != nil {
return nil, err
}
return h.Sum(nil), nil
}
// DeriveRootKey derives a root key for some path using the salt for the bucket and
// a password from the user. See the password key derivation design doc.
func DeriveRootKey(password, salt []byte, path storj.Path) (*storj.Key, error) {
mixedSalt, err := sha256hmac(password, salt)
if err != nil {
return nil, err
}
pathSalt, err := sha256hmac(mixedSalt, []byte(path))
if err != nil {
return nil, err
}
// use a time of 1, 64MB of ram, and all of the cores.
keyData := argon2.IDKey(password, pathSalt, 1, 64<<10, uint8(runtime.GOMAXPROCS(-1)), 32)
if len(keyData) != len(storj.Key{}) {
return nil, errs.New("invalid output from argon2id")
}
var key storj.Key
copy(key[:], keyData)
return &key, nil
}
// DeriveDefaultPassword combines a salt from the project with a user password to create
// a default password used for DeriveRootKey in the case that a single secret should be
// used to derive all of the bucket level secrets. See the password key derivation design
// doc.
func DeriveDefaultPassword(password, salt []byte) ([]byte, error) {
mixedSalt, err := sha256hmac(password, salt)
if err != nil {
return nil, err
}
// use a time of 1, 64MB of ram, and all of the cores.
return argon2.IDKey(password, mixedSalt, 1, 64<<10, uint8(runtime.GOMAXPROCS(-1)), 32), nil
}