| 
									
										
										
										
											2015-05-09 23:52:03 +02:00
										 |  |  | package repository | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											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. | 
					
						
							| 
									
										
										
										
											2019-06-12 18:40:05 +08:00
										 |  |  | 	ErrNoKeyFound = errors.New("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. | 
					
						
							| 
									
										
										
										
											2023-05-13 22:43:42 +02:00
										 |  |  | 	ErrMaxKeysReached = errors.New("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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-15 16:01:38 +02:00
										 |  |  | 	id restic.ID | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-28 23:14:32 +01: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(). | 
					
						
							| 
									
										
										
										
											2024-03-28 23:14:32 +01:00
										 |  |  | var params *crypto.Params | 
					
						
							| 
									
										
										
										
											2016-08-21 12:32:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-24 17:20:10 +01:00
										 |  |  | const ( | 
					
						
							| 
									
										
										
										
											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. | 
					
						
							| 
									
										
										
										
											2020-04-10 11:37:39 +02:00
										 |  |  | func createMasterKey(ctx context.Context, s *Repository, password string) (*Key, error) { | 
					
						
							|  |  |  | 	return AddKey(ctx, 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. | 
					
						
							| 
									
										
										
										
											2022-10-15 16:01:38 +02:00
										 |  |  | func OpenKey(ctx context.Context, s *Repository, id restic.ID, password string) (*Key, error) { | 
					
						
							|  |  |  | 	k, err := LoadKey(ctx, s, id) | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2022-10-15 16:01:38 +02:00
										 |  |  | 		debug.Log("LoadKey(%v) returned error %v", id.String(), 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 | 
					
						
							| 
									
										
										
										
											2017-10-29 11:33:57 +01:00
										 |  |  | 	nonce, ciphertext := k.Data[:k.user.NonceSize()], k.Data[k.user.NonceSize():] | 
					
						
							| 
									
										
										
										
											2017-11-01 09:58:59 +01:00
										 |  |  | 	buf, err := k.user.Open(nil, nonce, ciphertext, nil) | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 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
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-10-15 16:01:38 +02:00
										 |  |  | 	k.id = id | 
					
						
							| 
									
										
										
										
											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. | 
					
						
							| 
									
										
										
										
											2018-11-25 09:10:45 -05:00
										 |  |  | func SearchKey(ctx context.Context, s *Repository, password string, maxKeys int, keyHint string) (k *Key, err error) { | 
					
						
							| 
									
										
										
										
											2016-08-21 13:09:31 +02:00
										 |  |  | 	checked := 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-25 09:10:45 -05:00
										 |  |  | 	if len(keyHint) > 0 { | 
					
						
							| 
									
										
										
										
											2023-10-01 13:05:56 +02:00
										 |  |  | 		id, err := restic.Find(ctx, s, restic.KeyFile, keyHint) | 
					
						
							| 
									
										
										
										
											2018-11-25 09:10:45 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if err == nil { | 
					
						
							| 
									
										
										
										
											2022-10-15 16:01:38 +02:00
										 |  |  | 			key, err := OpenKey(ctx, s, id, password) | 
					
						
							| 
									
										
										
										
											2018-11-25 09:10:45 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if err == nil { | 
					
						
							|  |  |  | 				debug.Log("successfully opened hinted key %v", id) | 
					
						
							|  |  |  | 				return key, nil | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			debug.Log("could not open hinted key %v", id) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			debug.Log("Could not find hinted key %v", keyHint) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-11 13:22:13 +01:00
										 |  |  | 	listCtx, cancel := context.WithCancel(ctx) | 
					
						
							|  |  |  | 	defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// try at most maxKeys keys in repo | 
					
						
							| 
									
										
										
										
											2024-02-10 22:58:10 +01:00
										 |  |  | 	err = s.List(listCtx, restic.KeyFile, func(id restic.ID, _ int64) error { | 
					
						
							| 
									
										
										
										
											2022-05-30 15:54:32 +08:00
										 |  |  | 		checked++ | 
					
						
							| 
									
										
										
										
											2016-08-21 13:09:31 +02:00
										 |  |  | 		if maxKeys > 0 && checked > maxKeys { | 
					
						
							| 
									
										
										
										
											2018-01-21 17:25:36 +01:00
										 |  |  | 			return ErrMaxKeysReached | 
					
						
							| 
									
										
										
										
											2016-08-21 13:09:31 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-15 16:01:38 +02:00
										 |  |  | 		debug.Log("trying key %q", id.String()) | 
					
						
							|  |  |  | 		key, err := OpenKey(ctx, s, id, password) | 
					
						
							| 
									
										
										
										
											2017-12-14 19:13:01 +01:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2022-10-15 16:01:38 +02:00
										 |  |  | 			debug.Log("key %v returned error %v", id.String(), err) | 
					
						
							| 
									
										
										
										
											2016-08-21 13:09:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// ErrUnauthenticated means the password is wrong, try the next key | 
					
						
							| 
									
										
										
										
											2022-06-13 20:35:37 +02:00
										 |  |  | 			if errors.Is(err, crypto.ErrUnauthenticated) { | 
					
						
							| 
									
										
										
										
											2018-01-21 17:25:36 +01:00
										 |  |  | 				return nil | 
					
						
							| 
									
										
										
										
											2016-08-21 13:09:31 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-21 17:25:36 +01:00
										 |  |  | 			return err | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-15 16:01:38 +02:00
										 |  |  | 		debug.Log("successfully opened key %v", id.String()) | 
					
						
							| 
									
										
										
										
											2018-01-21 17:25:36 +01:00
										 |  |  | 		k = key | 
					
						
							| 
									
										
										
										
											2018-03-11 13:22:13 +01:00
										 |  |  | 		cancel() | 
					
						
							| 
									
										
										
										
											2018-01-21 17:25:36 +01:00
										 |  |  | 		return nil | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-11 13:22:13 +01:00
										 |  |  | 	if err == context.Canceled { | 
					
						
							|  |  |  | 		err = nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-21 17:25:36 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-21 17:25:36 +01:00
										 |  |  | 	if k == nil { | 
					
						
							|  |  |  | 		return nil, ErrNoKeyFound | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return k, nil | 
					
						
							| 
									
										
										
										
											2014-09-23 22:39:12 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-17 23:05:23 +01:00
										 |  |  | // LoadKey loads a key from the backend. | 
					
						
							| 
									
										
										
										
											2022-10-15 16:01:38 +02:00
										 |  |  | func LoadKey(ctx context.Context, s *Repository, id restic.ID) (k *Key, err error) { | 
					
						
							| 
									
										
										
										
											2023-10-01 11:40:12 +02:00
										 |  |  | 	h := backend.Handle{Type: restic.KeyFile, Name: id.String()} | 
					
						
							| 
									
										
										
										
											2019-03-24 21:59:14 +01:00
										 |  |  | 	data, err := backend.LoadAll(ctx, nil, 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. | 
					
						
							| 
									
										
										
										
											2019-06-26 09:37:08 +02:00
										 |  |  | func AddKey(ctx context.Context, s *Repository, password, username, hostname string, template *crypto.Key) (*Key, error) { | 
					
						
							| 
									
										
										
										
											2016-08-21 12:32:38 +02:00
										 |  |  | 	// make sure we have valid KDF parameters | 
					
						
							| 
									
										
										
										
											2024-03-28 23:14:32 +01: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
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-28 23:14:32 +01: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{ | 
					
						
							| 
									
										
										
										
											2019-06-26 09:37:08 +02:00
										 |  |  | 		Created:  time.Now(), | 
					
						
							|  |  |  | 		Username: username, | 
					
						
							|  |  |  | 		Hostname: hostname, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		KDF: "scrypt", | 
					
						
							| 
									
										
										
										
											2024-03-28 23:14:32 +01:00
										 |  |  | 		N:   params.N, | 
					
						
							|  |  |  | 		R:   params.R, | 
					
						
							|  |  |  | 		P:   params.P, | 
					
						
							| 
									
										
										
										
											2014-11-25 23:07:00 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-26 09:37:08 +02:00
										 |  |  | 	if newkey.Hostname == "" { | 
					
						
							|  |  |  | 		newkey.Hostname, _ = os.Hostname() | 
					
						
							| 
									
										
										
										
											2014-11-25 23:07:00 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-26 09:37:08 +02:00
										 |  |  | 	if newkey.Username == "" { | 
					
						
							|  |  |  | 		usr, err := user.Current() | 
					
						
							|  |  |  | 		if err == nil { | 
					
						
							|  |  |  | 			newkey.Username = usr.Username | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-11-25 23:07:00 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// generate random salt | 
					
						
							| 
									
										
										
										
											2019-06-26 09:37:08 +02:00
										 |  |  | 	var err error | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2024-03-28 23:14:32 +01: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-10-29 11:33:57 +01:00
										 |  |  | 	nonce := crypto.NewRandomNonce() | 
					
						
							| 
									
										
										
										
											2022-06-12 14:48:30 +02:00
										 |  |  | 	ciphertext := make([]byte, 0, crypto.CiphertextLength(len(buf))) | 
					
						
							| 
									
										
										
										
											2017-10-29 11:33:57 +01:00
										 |  |  | 	ciphertext = append(ciphertext, nonce...) | 
					
						
							|  |  |  | 	ciphertext = newkey.user.Seal(ciphertext, nonce, buf, nil) | 
					
						
							|  |  |  | 	newkey.Data = ciphertext | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-15 16:01:38 +02:00
										 |  |  | 	id := restic.Hash(buf) | 
					
						
							| 
									
										
										
										
											2014-11-25 23:07:00 +01:00
										 |  |  | 	// store in repository and return | 
					
						
							| 
									
										
										
										
											2023-10-01 11:40:12 +02:00
										 |  |  | 	h := backend.Handle{ | 
					
						
							| 
									
										
										
										
											2016-09-01 21:19:30 +02:00
										 |  |  | 		Type: restic.KeyFile, | 
					
						
							| 
									
										
										
										
											2022-10-15 16:01:38 +02:00
										 |  |  | 		Name: id.String(), | 
					
						
							| 
									
										
										
										
											2015-02-15 17:26:08 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-01 11:40:12 +02:00
										 |  |  | 	err = s.be.Save(ctx, h, backend.NewByteReader(buf, s.be.Hasher())) | 
					
						
							| 
									
										
										
										
											2015-02-15 17:26:08 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-15 16:01:38 +02:00
										 |  |  | 	newkey.id = id | 
					
						
							| 
									
										
										
										
											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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-21 20:38:42 +01:00
										 |  |  | func RemoveKey(ctx context.Context, repo *Repository, id restic.ID) error { | 
					
						
							|  |  |  | 	if id == repo.KeyID() { | 
					
						
							|  |  |  | 		return errors.New("refusing to remove key currently used to access repository") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	h := backend.Handle{Type: restic.KeyFile, Name: id.String()} | 
					
						
							|  |  |  | 	return repo.be.Remove(ctx, h) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-15 16:01:38 +02:00
										 |  |  | // ID returns an identifier for the key. | 
					
						
							|  |  |  | func (k Key) ID() restic.ID { | 
					
						
							|  |  |  | 	return k.id | 
					
						
							| 
									
										
										
										
											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() | 
					
						
							|  |  |  | } |