| 
									
										
										
										
											2015-05-09 23:52:03 +02:00
										 |  |  | package repository | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2017-01-22 12:32:20 +01:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2017-06-04 11:16:55 +02:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"os/user" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-23 14:21:03 +02:00
										 |  |  | 	"github.com/restic/restic/internal/errors" | 
					
						
							| 
									
										
										
										
											2017-07-24 17:42:25 +02:00
										 |  |  | 	"github.com/restic/restic/internal/restic" | 
					
						
							| 
									
										
										
										
											2017-07-23 14:21:03 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/backend" | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/crypto" | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/debug" | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							| 
									
										
										
										
											2014-11-15 17:17:24 +01:00
										 |  |  | 	// ErrNoKeyFound is returned when no key for the repository could be decrypted. | 
					
						
							| 
									
										
										
										
											2017-09-10 10:55:01 +02:00
										 |  |  | 	ErrNoKeyFound = errors.Fatal("wrong password or no key found") | 
					
						
							| 
									
										
										
										
											2016-08-21 13:09:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// ErrMaxKeysReached is returned when the maximum number of keys was checked and no key could be found. | 
					
						
							| 
									
										
										
										
											2017-09-10 10:55:01 +02:00
										 |  |  | 	ErrMaxKeysReached = errors.Fatal("maximum number of keys reached") | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-15 17:17:24 +01:00
										 |  |  | // Key represents an encrypted master key for a repository. | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | type Key struct { | 
					
						
							|  |  |  | 	Created  time.Time `json:"created"` | 
					
						
							|  |  |  | 	Username string    `json:"username"` | 
					
						
							|  |  |  | 	Hostname string    `json:"hostname"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	KDF  string `json:"kdf"` | 
					
						
							|  |  |  | 	N    int    `json:"N"` | 
					
						
							|  |  |  | 	R    int    `json:"r"` | 
					
						
							|  |  |  | 	P    int    `json:"p"` | 
					
						
							|  |  |  | 	Salt []byte `json:"salt"` | 
					
						
							|  |  |  | 	Data []byte `json:"data"` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-12 09:41:47 +02:00
										 |  |  | 	user   *crypto.Key | 
					
						
							|  |  |  | 	master *crypto.Key | 
					
						
							| 
									
										
										
										
											2014-11-25 23:18:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-28 11:50:23 +01:00
										 |  |  | 	name string | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-28 10:28:29 +02:00
										 |  |  | // Params tracks the parameters used for the KDF. If not set, it will be | 
					
						
							| 
									
										
										
										
											2016-08-21 12:32:38 +02:00
										 |  |  | // calibrated on the first run of AddKey(). | 
					
						
							| 
									
										
										
										
											2017-10-28 10:28:29 +02:00
										 |  |  | var Params *crypto.Params | 
					
						
							| 
									
										
										
										
											2016-08-21 12:32:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							| 
									
										
										
										
											2016-08-21 13:13:05 +02:00
										 |  |  | 	// KDFTimeout specifies the maximum runtime for the KDF. | 
					
						
							|  |  |  | 	KDFTimeout = 500 * time.Millisecond | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// KDFMemory limits the memory the KDF is allowed to use. | 
					
						
							|  |  |  | 	KDFMemory = 60 | 
					
						
							| 
									
										
										
										
											2016-08-21 12:32:38 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-03 17:37:12 +02:00
										 |  |  | // createMasterKey creates a new master key in the given backend and encrypts | 
					
						
							| 
									
										
										
										
											2015-05-03 17:17:10 +02:00
										 |  |  | // it with the password. | 
					
						
							| 
									
										
										
										
											2015-05-09 23:59:58 +02:00
										 |  |  | func createMasterKey(s *Repository, password string) (*Key, error) { | 
					
						
							| 
									
										
										
										
											2017-06-04 11:16:55 +02:00
										 |  |  | 	return AddKey(context.TODO(), s, password, nil) | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-28 11:50:23 +01:00
										 |  |  | // OpenKey tries do decrypt the key specified by name with the given password. | 
					
						
							| 
									
										
										
										
											2017-06-04 11:16:55 +02:00
										 |  |  | func OpenKey(ctx context.Context, s *Repository, name string, password string) (*Key, error) { | 
					
						
							|  |  |  | 	k, err := LoadKey(ctx, s, name) | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2017-09-10 15:35:02 +02:00
										 |  |  | 		debug.Log("LoadKey(%v) returned error %v", name, err) | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// check KDF | 
					
						
							|  |  |  | 	if k.KDF != "scrypt" { | 
					
						
							|  |  |  | 		return nil, errors.New("only supported KDF is scrypt()") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// derive user key | 
					
						
							| 
									
										
										
										
											2017-10-28 10:28:29 +02:00
										 |  |  | 	params := crypto.Params{ | 
					
						
							| 
									
										
										
										
											2016-08-21 12:32:38 +02:00
										 |  |  | 		N: k.N, | 
					
						
							|  |  |  | 		R: k.R, | 
					
						
							|  |  |  | 		P: k.P, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	k.user, err = crypto.KDF(params, k.Salt, password) | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-08-29 22:16:58 +02:00
										 |  |  | 		return nil, errors.Wrap(err, "crypto.KDF") | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// decrypt master keys | 
					
						
							| 
									
										
										
										
											2016-09-03 13:34:04 +02:00
										 |  |  | 	buf := make([]byte, len(k.Data)) | 
					
						
							| 
									
										
										
										
											2017-06-19 21:12:53 +02:00
										 |  |  | 	n, err := k.user.Decrypt(buf, k.Data) | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-09-03 13:34:04 +02:00
										 |  |  | 	buf = buf[:n] | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// restore json | 
					
						
							| 
									
										
										
										
											2015-04-12 09:41:47 +02:00
										 |  |  | 	k.master = &crypto.Key{} | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | 	err = json.Unmarshal(buf, k.master) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-09-27 22:35:08 +02:00
										 |  |  | 		debug.Log("Unmarshal() returned error %v", err) | 
					
						
							| 
									
										
										
										
											2016-08-29 22:16:58 +02:00
										 |  |  | 		return nil, errors.Wrap(err, "Unmarshal") | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-28 11:50:23 +01:00
										 |  |  | 	k.name = name | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-01 17:31:57 +02:00
										 |  |  | 	if !k.Valid() { | 
					
						
							|  |  |  | 		return nil, errors.New("Invalid key for repository") | 
					
						
							| 
									
										
										
										
											2015-04-06 00:22:19 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | 	return k, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-21 13:09:31 +02:00
										 |  |  | // SearchKey tries to decrypt at most maxKeys keys in the backend with the | 
					
						
							|  |  |  | // given password. If none could be found, ErrNoKeyFound is returned. When | 
					
						
							|  |  |  | // maxKeys is reached, ErrMaxKeysReached is returned. When setting maxKeys to | 
					
						
							|  |  |  | // zero, all keys in the repo are checked. | 
					
						
							| 
									
										
										
										
											2017-06-04 11:16:55 +02:00
										 |  |  | func SearchKey(ctx context.Context, s *Repository, password string, maxKeys int) (*Key, error) { | 
					
						
							| 
									
										
										
										
											2016-08-21 13:09:31 +02:00
										 |  |  | 	checked := 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// try at most maxKeysForSearch keys in repo | 
					
						
							| 
									
										
										
										
											2017-06-04 11:16:55 +02:00
										 |  |  | 	for name := range s.Backend().List(ctx, restic.KeyFile) { | 
					
						
							| 
									
										
										
										
											2016-08-21 13:09:31 +02:00
										 |  |  | 		if maxKeys > 0 && checked > maxKeys { | 
					
						
							|  |  |  | 			return nil, ErrMaxKeysReached | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-09 10:50:32 +02:00
										 |  |  | 		debug.Log("trying key %q", name) | 
					
						
							| 
									
										
										
										
											2017-06-04 11:16:55 +02:00
										 |  |  | 		key, err := OpenKey(ctx, s, name, password) | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2017-09-10 15:35:02 +02:00
										 |  |  | 			debug.Log("key %v returned error %v", name, err) | 
					
						
							| 
									
										
										
										
											2016-08-21 13:09:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// ErrUnauthenticated means the password is wrong, try the next key | 
					
						
							| 
									
										
										
										
											2016-08-29 19:18:57 +02:00
										 |  |  | 			if errors.Cause(err) == crypto.ErrUnauthenticated { | 
					
						
							| 
									
										
										
										
											2016-08-21 13:09:31 +02:00
										 |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-10 10:55:01 +02:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				debug.Log("unable to open key %v: %v\n", err) | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-10 15:35:02 +02:00
										 |  |  | 		debug.Log("successfully opened key %v", name) | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | 		return key, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil, ErrNoKeyFound | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-17 23:05:23 +01:00
										 |  |  | // LoadKey loads a key from the backend. | 
					
						
							| 
									
										
										
										
											2017-06-04 11:16:55 +02:00
										 |  |  | func LoadKey(ctx context.Context, s *Repository, name string) (k *Key, err error) { | 
					
						
							| 
									
										
										
										
											2016-09-01 21:19:30 +02:00
										 |  |  | 	h := restic.Handle{Type: restic.KeyFile, Name: name} | 
					
						
							| 
									
										
										
										
											2017-06-04 11:16:55 +02:00
										 |  |  | 	data, err := backend.LoadAll(ctx, s.be, h) | 
					
						
							| 
									
										
										
										
											2015-02-17 23:05:23 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-23 23:48:19 +01:00
										 |  |  | 	k = &Key{} | 
					
						
							|  |  |  | 	err = json.Unmarshal(data, k) | 
					
						
							| 
									
										
										
										
											2015-02-17 23:05:23 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-08-29 22:16:58 +02:00
										 |  |  | 		return nil, errors.Wrap(err, "Unmarshal") | 
					
						
							| 
									
										
										
										
											2015-02-17 23:05:23 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-18 20:33:20 +01:00
										 |  |  | 	return k, nil | 
					
						
							| 
									
										
										
										
											2015-02-17 23:05:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 23:07:00 +01:00
										 |  |  | // AddKey adds a new key to an already existing repository. | 
					
						
							| 
									
										
										
										
											2017-06-04 11:16:55 +02:00
										 |  |  | func AddKey(ctx context.Context, s *Repository, password string, template *crypto.Key) (*Key, error) { | 
					
						
							| 
									
										
										
										
											2016-08-21 12:32:38 +02:00
										 |  |  | 	// make sure we have valid KDF parameters | 
					
						
							| 
									
										
										
										
											2017-10-28 10:28:29 +02:00
										 |  |  | 	if Params == nil { | 
					
						
							| 
									
										
										
										
											2016-08-21 12:32:38 +02:00
										 |  |  | 		p, err := crypto.Calibrate(KDFTimeout, KDFMemory) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2016-08-29 22:16:58 +02:00
										 |  |  | 			return nil, errors.Wrap(err, "Calibrate") | 
					
						
							| 
									
										
										
										
											2016-08-21 12:32:38 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-28 10:28:29 +02:00
										 |  |  | 		Params = &p | 
					
						
							| 
									
										
										
										
											2016-09-27 22:35:08 +02:00
										 |  |  | 		debug.Log("calibrated KDF parameters are %v", p) | 
					
						
							| 
									
										
										
										
											2016-08-21 12:32:38 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 23:07:00 +01:00
										 |  |  | 	// fill meta data about key | 
					
						
							|  |  |  | 	newkey := &Key{ | 
					
						
							|  |  |  | 		Created: time.Now(), | 
					
						
							|  |  |  | 		KDF:     "scrypt", | 
					
						
							| 
									
										
										
										
											2017-10-28 10:28:29 +02:00
										 |  |  | 		N:       Params.N, | 
					
						
							|  |  |  | 		R:       Params.R, | 
					
						
							|  |  |  | 		P:       Params.P, | 
					
						
							| 
									
										
										
										
											2014-11-25 23:07:00 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hn, err := os.Hostname() | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		newkey.Hostname = hn | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	usr, err := user.Current() | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		newkey.Username = usr.Username | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// generate random salt | 
					
						
							| 
									
										
										
										
											2016-08-21 12:32:38 +02:00
										 |  |  | 	newkey.Salt, err = crypto.NewSalt() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		panic("unable to read enough random bytes for salt: " + err.Error()) | 
					
						
							| 
									
										
										
										
											2014-11-25 23:07:00 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-14 19:53:51 +01:00
										 |  |  | 	// call KDF to derive user key | 
					
						
							| 
									
										
										
										
											2017-10-28 10:28:29 +02:00
										 |  |  | 	newkey.user, err = crypto.KDF(*Params, newkey.Salt, password) | 
					
						
							| 
									
										
										
										
											2014-11-25 23:07:00 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-21 18:16:22 +01:00
										 |  |  | 	if template == nil { | 
					
						
							|  |  |  | 		// generate new random master keys | 
					
						
							| 
									
										
										
										
											2015-04-29 22:28:34 -04:00
										 |  |  | 		newkey.master = crypto.NewRandomKey() | 
					
						
							| 
									
										
										
										
											2014-12-21 18:16:22 +01:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		// copy master keys from old key | 
					
						
							| 
									
										
										
										
											2015-05-03 18:04:13 +02:00
										 |  |  | 		newkey.master = template | 
					
						
							| 
									
										
										
										
											2014-12-21 18:16:22 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-11-25 23:07:00 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// encrypt master keys (as json) with user key | 
					
						
							|  |  |  | 	buf, err := json.Marshal(newkey.master) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-08-29 22:16:58 +02:00
										 |  |  | 		return nil, errors.Wrap(err, "Marshal") | 
					
						
							| 
									
										
										
										
											2014-11-25 23:07:00 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-19 21:12:53 +02:00
										 |  |  | 	newkey.Data, err = newkey.user.Encrypt(nil, buf) | 
					
						
							| 
									
										
										
										
											2014-11-25 23:07:00 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// dump as json | 
					
						
							|  |  |  | 	buf, err = json.Marshal(newkey) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-08-29 22:16:58 +02:00
										 |  |  | 		return nil, errors.Wrap(err, "Marshal") | 
					
						
							| 
									
										
										
										
											2014-11-25 23:07:00 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// store in repository and return | 
					
						
							| 
									
										
										
										
											2016-08-31 20:29:54 +02:00
										 |  |  | 	h := restic.Handle{ | 
					
						
							| 
									
										
										
										
											2016-09-01 21:19:30 +02:00
										 |  |  | 		Type: restic.KeyFile, | 
					
						
							|  |  |  | 		Name: restic.Hash(buf).String(), | 
					
						
							| 
									
										
										
										
											2015-02-15 17:26:08 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-04 11:16:55 +02:00
										 |  |  | 	err = s.be.Save(ctx, h, bytes.NewReader(buf)) | 
					
						
							| 
									
										
										
										
											2015-02-15 17:26:08 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-24 17:52:44 +01:00
										 |  |  | 	newkey.name = h.Name | 
					
						
							| 
									
										
										
										
											2014-11-25 23:07:00 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-21 18:16:22 +01:00
										 |  |  | 	return newkey, nil | 
					
						
							| 
									
										
										
										
											2014-11-25 23:07:00 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | func (k *Key) String() string { | 
					
						
							|  |  |  | 	if k == nil { | 
					
						
							|  |  |  | 		return "<Key nil>" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return fmt.Sprintf("<Key of %s@%s, created on %s>", k.Username, k.Hostname, k.Created) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-11-25 23:18:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-23 23:27:40 +01:00
										 |  |  | // Name returns an identifier for the key. | 
					
						
							| 
									
										
										
										
											2015-03-28 11:50:23 +01:00
										 |  |  | func (k Key) Name() string { | 
					
						
							|  |  |  | 	return k.name | 
					
						
							| 
									
										
										
										
											2014-11-25 23:18:02 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-05-01 17:31:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Valid tests whether the mac and encryption keys are valid (i.e. not zero) | 
					
						
							|  |  |  | func (k *Key) Valid() bool { | 
					
						
							|  |  |  | 	return k.user.Valid() && k.master.Valid() | 
					
						
							|  |  |  | } |