github.com/fawick/restic@v0.1.1-0.20171126184616-c02923fbfc79/internal/crypto/crypto.go (about)

     1  package crypto
     2  
     3  import (
     4  	"crypto/aes"
     5  	"crypto/cipher"
     6  	"crypto/rand"
     7  	"encoding/json"
     8  	"fmt"
     9  
    10  	"github.com/restic/restic/internal/errors"
    11  
    12  	"golang.org/x/crypto/poly1305"
    13  )
    14  
    15  const (
    16  	aesKeySize  = 32                        // for AES-256
    17  	macKeySizeK = 16                        // for AES-128
    18  	macKeySizeR = 16                        // for Poly1305
    19  	macKeySize  = macKeySizeK + macKeySizeR // for Poly1305-AES128
    20  	ivSize      = aes.BlockSize
    21  
    22  	macSize = poly1305.TagSize
    23  
    24  	// Extension is the number of bytes a plaintext is enlarged by encrypting it.
    25  	Extension = ivSize + macSize
    26  )
    27  
    28  var (
    29  	// ErrUnauthenticated is returned when ciphertext verification has failed.
    30  	ErrUnauthenticated = errors.New("ciphertext verification failed")
    31  )
    32  
    33  // Key holds encryption and message authentication keys for a repository. It is stored
    34  // encrypted and authenticated as a JSON data structure in the Data field of the Key
    35  // structure.
    36  type Key struct {
    37  	MACKey        `json:"mac"`
    38  	EncryptionKey `json:"encrypt"`
    39  }
    40  
    41  // EncryptionKey is key used for encryption
    42  type EncryptionKey [32]byte
    43  
    44  // MACKey is used to sign (authenticate) data.
    45  type MACKey struct {
    46  	K [16]byte // for AES-128
    47  	R [16]byte // for Poly1305
    48  
    49  	masked bool // remember if the MAC key has already been masked
    50  }
    51  
    52  // mask for key, (cf. http://cr.yp.to/mac/poly1305-20050329.pdf)
    53  var poly1305KeyMask = [16]byte{
    54  	0xff,
    55  	0xff,
    56  	0xff,
    57  	0x0f, // 3: top four bits zero
    58  	0xfc, // 4: bottom two bits zero
    59  	0xff,
    60  	0xff,
    61  	0x0f, // 7: top four bits zero
    62  	0xfc, // 8: bottom two bits zero
    63  	0xff,
    64  	0xff,
    65  	0x0f, // 11: top four bits zero
    66  	0xfc, // 12: bottom two bits zero
    67  	0xff,
    68  	0xff,
    69  	0x0f, // 15: top four bits zero
    70  }
    71  
    72  func poly1305MAC(msg []byte, nonce []byte, key *MACKey) []byte {
    73  	k := poly1305PrepareKey(nonce, key)
    74  
    75  	var out [16]byte
    76  	poly1305.Sum(&out, msg, &k)
    77  
    78  	return out[:]
    79  }
    80  
    81  // mask poly1305 key
    82  func maskKey(k *MACKey) {
    83  	if k == nil || k.masked {
    84  		return
    85  	}
    86  
    87  	for i := 0; i < poly1305.TagSize; i++ {
    88  		k.R[i] = k.R[i] & poly1305KeyMask[i]
    89  	}
    90  
    91  	k.masked = true
    92  }
    93  
    94  // construct mac key from slice (k||r), with masking
    95  func macKeyFromSlice(mk *MACKey, data []byte) {
    96  	copy(mk.K[:], data[:16])
    97  	copy(mk.R[:], data[16:32])
    98  	maskKey(mk)
    99  }
   100  
   101  // prepare key for low-level poly1305.Sum(): r||n
   102  func poly1305PrepareKey(nonce []byte, key *MACKey) [32]byte {
   103  	var k [32]byte
   104  
   105  	maskKey(key)
   106  
   107  	cipher, err := aes.NewCipher(key.K[:])
   108  	if err != nil {
   109  		panic(err)
   110  	}
   111  	cipher.Encrypt(k[16:], nonce[:])
   112  
   113  	copy(k[:16], key.R[:])
   114  
   115  	return k
   116  }
   117  
   118  func poly1305Verify(msg []byte, nonce []byte, key *MACKey, mac []byte) bool {
   119  	k := poly1305PrepareKey(nonce, key)
   120  
   121  	var m [16]byte
   122  	copy(m[:], mac)
   123  
   124  	return poly1305.Verify(&m, msg, &k)
   125  }
   126  
   127  // NewRandomKey returns new encryption and message authentication keys.
   128  func NewRandomKey() *Key {
   129  	k := &Key{}
   130  
   131  	n, err := rand.Read(k.EncryptionKey[:])
   132  	if n != aesKeySize || err != nil {
   133  		panic("unable to read enough random bytes for encryption key")
   134  	}
   135  
   136  	n, err = rand.Read(k.MACKey.K[:])
   137  	if n != macKeySizeK || err != nil {
   138  		panic("unable to read enough random bytes for MAC encryption key")
   139  	}
   140  
   141  	n, err = rand.Read(k.MACKey.R[:])
   142  	if n != macKeySizeR || err != nil {
   143  		panic("unable to read enough random bytes for MAC key")
   144  	}
   145  
   146  	maskKey(&k.MACKey)
   147  	return k
   148  }
   149  
   150  // NewRandomNonce returns a new random nonce. It panics on error so that the
   151  // program is safely terminated.
   152  func NewRandomNonce() []byte {
   153  	iv := make([]byte, ivSize)
   154  	n, err := rand.Read(iv)
   155  	if n != ivSize || err != nil {
   156  		panic("unable to read enough random bytes for iv")
   157  	}
   158  	return iv
   159  }
   160  
   161  type jsonMACKey struct {
   162  	K []byte `json:"k"`
   163  	R []byte `json:"r"`
   164  }
   165  
   166  // MarshalJSON converts the MACKey to JSON.
   167  func (m *MACKey) MarshalJSON() ([]byte, error) {
   168  	return json.Marshal(jsonMACKey{K: m.K[:], R: m.R[:]})
   169  }
   170  
   171  // UnmarshalJSON fills the key m with data from the JSON representation.
   172  func (m *MACKey) UnmarshalJSON(data []byte) error {
   173  	j := jsonMACKey{}
   174  	err := json.Unmarshal(data, &j)
   175  	if err != nil {
   176  		return errors.Wrap(err, "Unmarshal")
   177  	}
   178  	copy(m.K[:], j.K)
   179  	copy(m.R[:], j.R)
   180  
   181  	return nil
   182  }
   183  
   184  // Valid tests whether the key k is valid (i.e. not zero).
   185  func (m *MACKey) Valid() bool {
   186  	nonzeroK := false
   187  	for i := 0; i < len(m.K); i++ {
   188  		if m.K[i] != 0 {
   189  			nonzeroK = true
   190  		}
   191  	}
   192  
   193  	if !nonzeroK {
   194  		return false
   195  	}
   196  
   197  	for i := 0; i < len(m.R); i++ {
   198  		if m.R[i] != 0 {
   199  			return true
   200  		}
   201  	}
   202  
   203  	return false
   204  }
   205  
   206  // MarshalJSON converts the EncryptionKey to JSON.
   207  func (k *EncryptionKey) MarshalJSON() ([]byte, error) {
   208  	return json.Marshal(k[:])
   209  }
   210  
   211  // UnmarshalJSON fills the key k with data from the JSON representation.
   212  func (k *EncryptionKey) UnmarshalJSON(data []byte) error {
   213  	d := make([]byte, aesKeySize)
   214  	err := json.Unmarshal(data, &d)
   215  	if err != nil {
   216  		return errors.Wrap(err, "Unmarshal")
   217  	}
   218  	copy(k[:], d)
   219  
   220  	return nil
   221  }
   222  
   223  // Valid tests whether the key k is valid (i.e. not zero).
   224  func (k *EncryptionKey) Valid() bool {
   225  	for i := 0; i < len(k); i++ {
   226  		if k[i] != 0 {
   227  			return true
   228  		}
   229  	}
   230  
   231  	return false
   232  }
   233  
   234  // ErrInvalidCiphertext is returned when trying to encrypt into the slice that
   235  // holds the plaintext.
   236  var ErrInvalidCiphertext = errors.New("invalid ciphertext, same slice used for plaintext")
   237  
   238  // validNonce checks that nonce is not all zero.
   239  func validNonce(nonce []byte) bool {
   240  	var sum byte
   241  	for _, b := range nonce {
   242  		sum |= b
   243  	}
   244  	return sum > 0
   245  }
   246  
   247  // statically ensure that *Key implements crypto/cipher.AEAD
   248  var _ cipher.AEAD = &Key{}
   249  
   250  // NonceSize returns the size of the nonce that must be passed to Seal
   251  // and Open.
   252  func (k *Key) NonceSize() int {
   253  	return ivSize
   254  }
   255  
   256  // Overhead returns the maximum difference between the lengths of a
   257  // plaintext and its ciphertext.
   258  func (k *Key) Overhead() int {
   259  	return macSize
   260  }
   261  
   262  // sliceForAppend takes a slice and a requested number of bytes. It returns a
   263  // slice with the contents of the given slice followed by that many bytes and a
   264  // second slice that aliases into it and contains only the extra bytes. If the
   265  // original slice has sufficient capacity then no allocation is performed.
   266  //
   267  // taken from the stdlib, crypto/aes/aes_gcm.go
   268  func sliceForAppend(in []byte, n int) (head, tail []byte) {
   269  	if total := len(in) + n; cap(in) >= total {
   270  		head = in[:total]
   271  	} else {
   272  		head = make([]byte, total)
   273  		copy(head, in)
   274  	}
   275  	tail = head[len(in):]
   276  	return
   277  }
   278  
   279  // Seal encrypts and authenticates plaintext, authenticates the
   280  // additional data and appends the result to dst, returning the updated
   281  // slice. The nonce must be NonceSize() bytes long and unique for all
   282  // time, for a given key.
   283  //
   284  // The plaintext and dst may alias exactly or not at all. To reuse
   285  // plaintext's storage for the encrypted output, use plaintext[:0] as dst.
   286  func (k *Key) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
   287  	if !k.Valid() {
   288  		panic("key is invalid")
   289  	}
   290  
   291  	if len(additionalData) > 0 {
   292  		panic("additional data is not supported")
   293  	}
   294  
   295  	if len(nonce) != ivSize {
   296  		panic("incorrect nonce length")
   297  	}
   298  
   299  	if !validNonce(nonce) {
   300  		panic("nonce is invalid")
   301  	}
   302  
   303  	ret, out := sliceForAppend(dst, len(plaintext)+k.Overhead())
   304  
   305  	c, err := aes.NewCipher(k.EncryptionKey[:])
   306  	if err != nil {
   307  		panic(fmt.Sprintf("unable to create cipher: %v", err))
   308  	}
   309  	e := cipher.NewCTR(c, nonce)
   310  	e.XORKeyStream(out, plaintext)
   311  
   312  	mac := poly1305MAC(out[:len(plaintext)], nonce, &k.MACKey)
   313  	copy(out[len(plaintext):], mac)
   314  
   315  	return ret
   316  }
   317  
   318  // Open decrypts and authenticates ciphertext, authenticates the
   319  // additional data and, if successful, appends the resulting plaintext
   320  // to dst, returning the updated slice. The nonce must be NonceSize()
   321  // bytes long and both it and the additional data must match the
   322  // value passed to Seal.
   323  //
   324  // The ciphertext and dst may alias exactly or not at all. To reuse
   325  // ciphertext's storage for the decrypted output, use ciphertext[:0] as dst.
   326  //
   327  // Even if the function fails, the contents of dst, up to its capacity,
   328  // may be overwritten.
   329  func (k *Key) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
   330  	if !k.Valid() {
   331  		return nil, errors.New("invalid key")
   332  	}
   333  
   334  	// check parameters
   335  	if len(nonce) != ivSize {
   336  		panic("incorrect nonce length")
   337  	}
   338  
   339  	if !validNonce(nonce) {
   340  		return nil, errors.New("nonce is invalid")
   341  	}
   342  
   343  	// check for plausible length
   344  	if len(ciphertext) < k.Overhead() {
   345  		return nil, errors.Errorf("trying to decrypt invalid data: ciphertext too small")
   346  	}
   347  
   348  	l := len(ciphertext) - macSize
   349  	ct, mac := ciphertext[:l], ciphertext[l:]
   350  
   351  	// verify mac
   352  	if !poly1305Verify(ct, nonce, &k.MACKey, mac) {
   353  		return nil, ErrUnauthenticated
   354  	}
   355  
   356  	ret, out := sliceForAppend(dst, len(ct))
   357  
   358  	c, err := aes.NewCipher(k.EncryptionKey[:])
   359  	if err != nil {
   360  		panic(fmt.Sprintf("unable to create cipher: %v", err))
   361  	}
   362  	e := cipher.NewCTR(c, nonce)
   363  	e.XORKeyStream(out, ct)
   364  
   365  	return ret, nil
   366  }
   367  
   368  // Valid tests if the key is valid.
   369  func (k *Key) Valid() bool {
   370  	return k.EncryptionKey.Valid() && k.MACKey.Valid()
   371  }