simplified vault credentials

This commit is contained in:
Jarek Kowalski
2016-05-20 06:34:45 -07:00
parent 49e0d6d19c
commit cfea61d833
5 changed files with 84 additions and 102 deletions

View File

@@ -100,12 +100,11 @@ func runCreateCommand(context *kingpin.ParseContext) error {
repoFormat.ObjectFormat,
repoFormat.MaxBlobSize)
masterKey, password, err := getKeyOrPassword(true)
creds, err := getVaultCredentials(true)
if err != nil {
return fmt.Errorf("unable to get credentials: %v", err)
}
var vlt *vault.Vault
vf, err := vaultFormat()
if err != nil {
return fmt.Errorf("unable to initialize vault format: %v", err)
@@ -115,11 +114,7 @@ func runCreateCommand(context *kingpin.ParseContext) error {
"Initializing vault in '%s' with encryption '%v'.\n",
vaultStorage.Configuration().Config.ToURL().String(),
vf.Encryption)
if masterKey != nil {
vlt, err = vault.CreateWithMasterKey(vaultStorage, vf, masterKey)
} else {
vlt, err = vault.CreateWithPassword(vaultStorage, vf, password)
}
vlt, err := vault.Create(vaultStorage, vf, creds)
if err != nil {
return fmt.Errorf("cannot create vault: %v", err)
}

View File

@@ -118,50 +118,46 @@ func openVaultSpecifiedByFlag() (*vault.Vault, error) {
return nil, err
}
masterKey, password, err := getKeyOrPassword(false)
creds, err := getVaultCredentials(false)
if err != nil {
return nil, err
}
if masterKey != nil {
return vault.OpenWithMasterKey(storage, masterKey)
}
return vault.OpenWithPassword(storage, password)
return vault.Open(storage, creds)
}
var errPasswordTooShort = errors.New("password too short")
func getKeyOrPassword(isNew bool) ([]byte, string, error) {
func getVaultCredentials(isNew bool) (vault.Credentials, error) {
if *key != "" {
k, err := hex.DecodeString(*key)
if err != nil {
return nil, "", fmt.Errorf("invalid key format: %v", err)
return nil, fmt.Errorf("invalid key format: %v", err)
}
return k, "", nil
return vault.MasterKey(k)
}
if *password != "" {
return nil, strings.TrimSpace(*password), nil
return vault.Password(strings.TrimSpace(*password))
}
if *keyFile != "" {
key, err := ioutil.ReadFile(*keyFile)
if err != nil {
return nil, "", fmt.Errorf("unable to read key file: %v", err)
return nil, fmt.Errorf("unable to read key file: %v", err)
}
return key, "", nil
return vault.MasterKey(key)
}
if *passwordFile != "" {
f, err := ioutil.ReadFile(*passwordFile)
if err != nil {
return nil, "", fmt.Errorf("unable to read password file: %v", err)
return nil, fmt.Errorf("unable to read password file: %v", err)
}
return nil, strings.TrimSpace(string(f)), nil
return vault.Password(strings.TrimSpace(string(f)))
}
if isNew {
for {
@@ -174,28 +170,28 @@ func getKeyOrPassword(isNew bool) ([]byte, string, error) {
continue
}
if err != nil {
return nil, "", err
return nil, err
}
fmt.Printf("Re-enter password for verification: ")
p2, err := askPass()
if err != nil {
return nil, "", err
return nil, err
}
fmt.Println()
if p1 != p2 {
fmt.Println("Passwords don't match!")
} else {
return nil, p1, nil
return vault.Password(p1)
}
}
} else {
fmt.Printf("Enter password to open vault: ")
p1, err := askPass()
if err != nil {
return nil, "", err
return nil, err
}
fmt.Println()
return nil, p1, nil
return vault.Password(p1)
}
}

57
vault/creds.go Normal file
View File

@@ -0,0 +1,57 @@
package vault
import (
"crypto/sha256"
"fmt"
"golang.org/x/crypto/pbkdf2"
)
const (
passwordBasedKeySize = 32
pbkdf2Rounds = 10000
// MinPasswordLength is the minimum allowed length of a password in charcters.
MinPasswordLength = 12
// MinMasterKeyLength is the minimum allowed length of a master key, in bytes.
MinMasterKeyLength = 16
)
// Credentials em
type Credentials interface {
getMasterKey(salt []byte) []byte
}
type masterKeyCredentials struct {
key []byte
}
func (mkc *masterKeyCredentials) getMasterKey(salt []byte) []byte {
return mkc.key
}
func MasterKey(key []byte) (Credentials, error) {
if len(key) < MinMasterKeyLength {
return nil, fmt.Errorf("master key too short")
}
return &masterKeyCredentials{key}, nil
}
type passwordCredentials struct {
password string
}
func (pc *passwordCredentials) getMasterKey(salt []byte) []byte {
return pbkdf2.Key([]byte(pc.password), salt, pbkdf2Rounds, passwordBasedKeySize, sha256.New)
}
func Password(password string) (Credentials, error) {
if len(password) < MinPasswordLength {
return nil, fmt.Errorf("password too short")
}
return &passwordCredentials{password}, nil
}

View File

@@ -1,47 +0,0 @@
package vault
import (
"errors"
"golang.org/x/crypto/curve25519"
)
const (
pbkdf2Rounds = 10000
masterKeySize = 32
)
// UserPrivateKey encapsulates secret key belonging to a user.
type UserPrivateKey struct {
key [32]byte
}
// UserPublicKey encapsulates public key belonging to a user.
type UserPublicKey struct {
key [32]byte
}
// Bytes returns the private key bytes.
func (prv UserPrivateKey) Bytes() []byte {
r := make([]byte, 32)
copy(r, prv.key[:])
return r
}
// PublicKey returns public key associated with the private key.
func (prv UserPrivateKey) PublicKey() *UserPublicKey {
pub := &UserPublicKey{}
curve25519.ScalarBaseMult(&pub.key, &prv.key)
return pub
}
func newPrivateKey(key []byte) (*UserPrivateKey, error) {
if len(key) != 32 {
return nil, errors.New("unsupported key length")
}
k := &UserPrivateKey{}
copy(k.key[:], key)
return k, nil
}

View File

@@ -17,19 +17,12 @@
"github.com/kopia/kopia/repo"
"golang.org/x/crypto/hkdf"
"golang.org/x/crypto/pbkdf2"
)
const (
formatBlock = "format"
checksumBlock = "checksum"
repositoryConfigBlock = "repo"
// MinPasswordLength is the minimum allowed length of a password in charcters.
MinPasswordLength = 12
// MinMasterKeyLength is the minimum allowed length of a master key, in bytes.
MinMasterKeyLength = 16
)
var (
@@ -216,35 +209,23 @@ func (v *Vault) List(prefix string) ([]string, error) {
return result, nil
}
// CreateWithPassword creates a password-protected Vault in the specified storage.
func CreateWithPassword(storage blob.Storage, format *Format, password string) (*Vault, error) {
// Create creates a Vault in the specified storage.
func Create(storage blob.Storage, format *Format, creds Credentials) (*Vault, error) {
if err := format.ensureUniqueID(); err != nil {
return nil, err
}
if len(password) < MinPasswordLength {
return nil, fmt.Errorf("password too short, must be at least %v characters, got %v", MinPasswordLength, len(password))
}
masterKey := pbkdf2.Key([]byte(password), format.UniqueID, pbkdf2Rounds, masterKeySize, sha256.New)
return CreateWithMasterKey(storage, format, masterKey)
}
// CreateWithMasterKey creates a master key-protected Vault in the specified storage.
func CreateWithMasterKey(storage blob.Storage, format *Format, masterKey []byte) (*Vault, error) {
if len(masterKey) < MinMasterKeyLength {
return nil, fmt.Errorf("key too short, must be at least %v bytes, got %v", MinMasterKeyLength, len(masterKey))
}
v := Vault{
Storage: storage,
MasterKey: masterKey,
Format: *format,
Storage: storage,
Format: *format,
}
v.Format.Version = "1"
if err := v.Format.ensureUniqueID(); err != nil {
return nil, err
}
v.MasterKey = creds.getMasterKey(v.Format.UniqueID)
formatBytes, err := json.Marshal(&v.Format)
if err != nil {
return nil, err
@@ -264,11 +245,11 @@ func CreateWithMasterKey(storage blob.Storage, format *Format, masterKey []byte)
return nil, err
}
return OpenWithMasterKey(storage, masterKey)
return Open(storage, creds)
}
// OpenWithPassword opens a password-protected vault.
func OpenWithPassword(storage blob.Storage, password string) (*Vault, error) {
// OpenWithPassword opens a vault.
func Open(storage blob.Storage, creds Credentials) (*Vault, error) {
v := Vault{
Storage: storage,
}
@@ -283,7 +264,7 @@ func OpenWithPassword(storage blob.Storage, password string) (*Vault, error) {
return nil, err
}
v.MasterKey = pbkdf2.Key([]byte(password), v.Format.UniqueID, pbkdf2Rounds, masterKeySize, sha256.New)
v.MasterKey = creds.getMasterKey(v.Format.UniqueID)
if _, err := v.readEncryptedBlock(checksumBlock); err != nil {
return nil, err