2
2
mirror of https://github.com/octoleo/restic.git synced 2024-11-22 04:45:15 +00:00

Document crypto and master key JSON struct

This commit is contained in:
Alexander Neumann 2015-03-22 21:03:01 +01:00
parent 65a653693e
commit 0ed2a066a0
4 changed files with 88 additions and 18 deletions

View File

@ -23,11 +23,11 @@ func init() {
}
func (cmd CmdCat) Usage() string {
return "[data|tree|snapshot|key|lock] ID"
return "[data|tree|snapshot|key|masterkey|lock] ID"
}
func (cmd CmdCat) Execute(args []string) error {
if len(args) != 2 {
if len(args) < 1 || (args[0] != "masterkey" && len(args) != 2) {
return fmt.Errorf("type or ID not specified, Usage: %s", cmd.Usage())
}
@ -38,7 +38,9 @@ func (cmd CmdCat) Execute(args []string) error {
tpe := args[0]
id, err := backend.ParseID(args[1])
var id backend.ID
if tpe != "masterkey" {
id, err = backend.ParseID(args[1])
if err != nil {
id = nil
@ -52,6 +54,7 @@ func (cmd CmdCat) Execute(args []string) error {
return err
}
}
}
switch tpe {
case "data":
@ -114,7 +117,14 @@ func (cmd CmdCat) Execute(args []string) error {
}
fmt.Println(string(buf))
return nil
case "masterkey":
buf, err := json.MarshalIndent(s.Key().Master(), "", " ")
if err != nil {
return err
}
fmt.Println(string(buf))
return nil
case "lock":
return errors.New("not yet implemented")

View File

@ -5,6 +5,7 @@ import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/json"
"fmt"
"io"
"io/ioutil"
@ -147,6 +148,42 @@ func generateRandomIV() (iv IV) {
return
}
type jsonMACKey struct {
K []byte `json:"k"`
R []byte `json:"r"`
}
func (m *MACKey) MarshalJSON() ([]byte, error) {
return json.Marshal(jsonMACKey{K: m.K[:], R: m.R[:]})
}
func (m *MACKey) UnmarshalJSON(data []byte) error {
j := jsonMACKey{}
err := json.Unmarshal(data, &j)
if err != nil {
return err
}
copy(m.K[:], j.K)
copy(m.R[:], j.R)
return nil
}
func (k *AESKey) MarshalJSON() ([]byte, error) {
return json.Marshal(k[:])
}
func (k *AESKey) UnmarshalJSON(data []byte) error {
d := make([]byte, AESKeySize)
err := json.Unmarshal(data, &d)
if err != nil {
return err
}
copy(k[:], d)
return nil
}
// Encrypt encrypts and signs data. Stored in ciphertext is IV || Ciphertext ||
// MAC. Encrypt returns the ciphertext's length.
func Encrypt(ks *MasterKeys, ciphertext, plaintext []byte) (int, error) {

View File

@ -107,9 +107,21 @@ last 32 byte). If the password is incorrect or the key file has been tampered
with, the computed MAC will not match the last 16 bytes of the data, and
restic exits with an error. Otherwise, the data is decrypted with the
encryption key derived from `scrypt`. This yields a JSON document which
contains the master signing and encryption keys for this repository. All data
in the repository is encrypted and signed with these master keys with AES-256
in Counter mode and signed with Poly1305-AES as described above.
contains the master signing and encryption keys for this repository, encoded in
Base64. The command `restic cat masterkey` can be used as follows to decrypt
and pretty-print the master key:
$ restic -r /tmp/restic-repo cat masterkey
{
"sign": {
"k": "evFWd9wWlndL9jc501268g==",
"r": "E9eEDnSJZgqwTOkDtOp+Dw=="
},
"encrypt": "UQCqa0lKZ94PygPxMRqkePTZnHRYh1k1pX2k2lM2v3Q="
}
All data in the repository is encrypted and signed with these master keys with
AES-256 in Counter mode and signed with Poly1305-AES as described above.
A repository can have several different passwords, with a key file for each.
This way, the password can be changed without having to re-encrypt all data.

15
key.go
View File

@ -64,8 +64,8 @@ type Key struct {
// encrypted and signed as a JSON data structure in the Data field of the Key
// structure.
type MasterKeys struct {
Sign MACKey
Encrypt AESKey
Sign MACKey `json:"sign"`
Encrypt AESKey `json:"encrypt"`
}
// CreateKey initializes a master key in the given backend and encrypts it with
@ -304,6 +304,17 @@ func (k *Key) DecryptUserFrom(rd io.Reader) (io.ReadCloser, error) {
return DecryptFrom(k.user, rd)
}
// Master() returns the master keys for this repository. Only included for
// debug purposes.
func (k *Key) Master() *MasterKeys {
return k.master
}
// User() returns the user keys for this key. Only included for debug purposes.
func (k *Key) User() *MasterKeys {
return k.user
}
func (k *Key) String() string {
if k == nil {
return "<Key nil>"