2015-04-12 07:36:14 +00:00
|
|
|
package crypto
|
2015-03-14 18:53:51 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/aes"
|
|
|
|
"crypto/cipher"
|
|
|
|
"crypto/rand"
|
2015-03-22 20:03:01 +00:00
|
|
|
"encoding/json"
|
2015-03-14 18:53:51 +00:00
|
|
|
"fmt"
|
|
|
|
|
2017-07-23 12:21:03 +00:00
|
|
|
"github.com/restic/restic/internal/errors"
|
2016-08-21 15:46:23 +00:00
|
|
|
|
2015-03-14 18:53:51 +00:00
|
|
|
"golang.org/x/crypto/poly1305"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2015-04-30 02:28:34 +00:00
|
|
|
aesKeySize = 32 // for AES-256
|
2015-04-12 07:41:47 +00:00
|
|
|
macKeySizeK = 16 // for AES-128
|
|
|
|
macKeySizeR = 16 // for Poly1305
|
|
|
|
macKeySize = macKeySizeK + macKeySizeR // for Poly1305-AES128
|
2015-03-22 18:09:30 +00:00
|
|
|
ivSize = aes.BlockSize
|
2015-04-12 07:36:14 +00:00
|
|
|
|
2017-06-19 19:12:53 +00:00
|
|
|
macSize = poly1305.TagSize
|
|
|
|
|
|
|
|
// Extension is the number of bytes a plaintext is enlarged by encrypting it.
|
2015-04-12 07:41:47 +00:00
|
|
|
Extension = ivSize + macSize
|
2015-04-12 07:36:14 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
// ErrUnauthenticated is returned when ciphertext verification has failed.
|
|
|
|
ErrUnauthenticated = errors.New("ciphertext verification failed")
|
2015-03-14 18:53:51 +00:00
|
|
|
)
|
|
|
|
|
2015-04-30 16:09:08 +00:00
|
|
|
// Key holds encryption and message authentication keys for a repository. It is stored
|
|
|
|
// encrypted and authenticated as a JSON data structure in the Data field of the Key
|
2015-05-03 15:51:04 +00:00
|
|
|
// structure.
|
2015-04-12 07:41:47 +00:00
|
|
|
type Key struct {
|
2017-06-19 19:12:53 +00:00
|
|
|
MACKey `json:"mac"`
|
|
|
|
EncryptionKey `json:"encrypt"`
|
2015-04-12 07:36:14 +00:00
|
|
|
}
|
|
|
|
|
2017-06-19 19:12:53 +00:00
|
|
|
// EncryptionKey is key used for encryption
|
2015-04-12 08:53:46 +00:00
|
|
|
type EncryptionKey [32]byte
|
2017-06-19 19:12:53 +00:00
|
|
|
|
|
|
|
// MACKey is used to sign (authenticate) data.
|
2015-04-30 16:09:08 +00:00
|
|
|
type MACKey struct {
|
2015-04-30 02:28:34 +00:00
|
|
|
K [16]byte // for AES-128
|
|
|
|
R [16]byte // for Poly1305
|
2015-04-26 11:07:26 +00:00
|
|
|
|
2015-04-30 16:09:08 +00:00
|
|
|
masked bool // remember if the MAC key has already been masked
|
2015-03-22 18:09:30 +00:00
|
|
|
}
|
2015-03-14 18:53:51 +00:00
|
|
|
|
|
|
|
// mask for key, (cf. http://cr.yp.to/mac/poly1305-20050329.pdf)
|
|
|
|
var poly1305KeyMask = [16]byte{
|
|
|
|
0xff,
|
|
|
|
0xff,
|
|
|
|
0xff,
|
|
|
|
0x0f, // 3: top four bits zero
|
|
|
|
0xfc, // 4: bottom two bits zero
|
|
|
|
0xff,
|
|
|
|
0xff,
|
|
|
|
0x0f, // 7: top four bits zero
|
|
|
|
0xfc, // 8: bottom two bits zero
|
|
|
|
0xff,
|
|
|
|
0xff,
|
|
|
|
0x0f, // 11: top four bits zero
|
|
|
|
0xfc, // 12: bottom two bits zero
|
|
|
|
0xff,
|
|
|
|
0xff,
|
|
|
|
0x0f, // 15: top four bits zero
|
|
|
|
}
|
|
|
|
|
2015-04-30 16:09:08 +00:00
|
|
|
func poly1305MAC(msg []byte, nonce []byte, key *MACKey) []byte {
|
2015-04-30 02:28:34 +00:00
|
|
|
k := poly1305PrepareKey(nonce, key)
|
2015-03-14 18:53:51 +00:00
|
|
|
|
|
|
|
var out [16]byte
|
|
|
|
poly1305.Sum(&out, msg, &k)
|
|
|
|
|
|
|
|
return out[:]
|
|
|
|
}
|
|
|
|
|
|
|
|
// mask poly1305 key
|
2015-04-30 16:09:08 +00:00
|
|
|
func maskKey(k *MACKey) {
|
2015-04-30 02:28:34 +00:00
|
|
|
if k == nil || k.masked {
|
2015-03-14 18:53:51 +00:00
|
|
|
return
|
|
|
|
}
|
2015-04-30 02:28:34 +00:00
|
|
|
|
2015-03-14 18:53:51 +00:00
|
|
|
for i := 0; i < poly1305.TagSize; i++ {
|
2015-03-22 18:09:30 +00:00
|
|
|
k.R[i] = k.R[i] & poly1305KeyMask[i]
|
2015-03-14 18:53:51 +00:00
|
|
|
}
|
2015-04-26 11:07:26 +00:00
|
|
|
|
|
|
|
k.masked = true
|
2015-03-14 18:53:51 +00:00
|
|
|
}
|
|
|
|
|
2015-03-22 18:09:30 +00:00
|
|
|
// construct mac key from slice (k||r), with masking
|
2015-04-30 16:09:08 +00:00
|
|
|
func macKeyFromSlice(mk *MACKey, data []byte) {
|
2015-03-22 18:09:30 +00:00
|
|
|
copy(mk.K[:], data[:16])
|
|
|
|
copy(mk.R[:], data[16:32])
|
|
|
|
maskKey(mk)
|
|
|
|
}
|
|
|
|
|
2015-04-30 02:28:34 +00:00
|
|
|
// prepare key for low-level poly1305.Sum(): r||n
|
2015-04-30 16:09:08 +00:00
|
|
|
func poly1305PrepareKey(nonce []byte, key *MACKey) [32]byte {
|
2015-03-14 18:53:51 +00:00
|
|
|
var k [32]byte
|
|
|
|
|
2015-04-30 02:28:34 +00:00
|
|
|
maskKey(key)
|
2015-03-14 18:53:51 +00:00
|
|
|
|
2015-03-22 18:09:30 +00:00
|
|
|
cipher, err := aes.NewCipher(key.K[:])
|
2015-03-14 18:53:51 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
cipher.Encrypt(k[16:], nonce[:])
|
|
|
|
|
2015-03-22 18:09:30 +00:00
|
|
|
copy(k[:16], key.R[:])
|
2015-03-14 18:53:51 +00:00
|
|
|
|
2015-04-30 02:28:34 +00:00
|
|
|
return k
|
|
|
|
}
|
|
|
|
|
2015-04-30 16:09:08 +00:00
|
|
|
func poly1305Verify(msg []byte, nonce []byte, key *MACKey, mac []byte) bool {
|
2015-04-30 02:28:34 +00:00
|
|
|
k := poly1305PrepareKey(nonce, key)
|
|
|
|
|
2015-03-14 18:53:51 +00:00
|
|
|
var m [16]byte
|
|
|
|
copy(m[:], mac)
|
|
|
|
|
|
|
|
return poly1305.Verify(&m, msg, &k)
|
|
|
|
}
|
|
|
|
|
2015-04-30 16:09:08 +00:00
|
|
|
// NewRandomKey returns new encryption and message authentication keys.
|
2015-04-30 02:28:34 +00:00
|
|
|
func NewRandomKey() *Key {
|
|
|
|
k := &Key{}
|
|
|
|
|
2017-06-19 19:12:53 +00:00
|
|
|
n, err := rand.Read(k.EncryptionKey[:])
|
2015-04-12 07:41:47 +00:00
|
|
|
if n != aesKeySize || err != nil {
|
2015-03-14 18:53:51 +00:00
|
|
|
panic("unable to read enough random bytes for encryption key")
|
|
|
|
}
|
|
|
|
|
2017-06-19 19:12:53 +00:00
|
|
|
n, err = rand.Read(k.MACKey.K[:])
|
2015-04-12 07:41:47 +00:00
|
|
|
if n != macKeySizeK || err != nil {
|
2015-04-30 16:09:08 +00:00
|
|
|
panic("unable to read enough random bytes for MAC encryption key")
|
2015-03-14 18:53:51 +00:00
|
|
|
}
|
|
|
|
|
2017-06-19 19:12:53 +00:00
|
|
|
n, err = rand.Read(k.MACKey.R[:])
|
2015-04-12 07:41:47 +00:00
|
|
|
if n != macKeySizeR || err != nil {
|
2015-04-30 16:09:08 +00:00
|
|
|
panic("unable to read enough random bytes for MAC key")
|
2015-03-22 18:09:30 +00:00
|
|
|
}
|
2015-03-14 18:53:51 +00:00
|
|
|
|
2017-06-19 19:12:53 +00:00
|
|
|
maskKey(&k.MACKey)
|
2015-03-22 18:18:34 +00:00
|
|
|
return k
|
2015-03-14 18:53:51 +00:00
|
|
|
}
|
|
|
|
|
2017-10-28 08:59:55 +00:00
|
|
|
// NewRandomNonce returns a new random nonce. It panics on error so that the
|
|
|
|
// program is safely terminated.
|
|
|
|
func NewRandomNonce() []byte {
|
2015-04-15 18:51:52 +00:00
|
|
|
iv := make([]byte, ivSize)
|
|
|
|
n, err := rand.Read(iv)
|
2015-03-14 18:53:51 +00:00
|
|
|
if n != ivSize || err != nil {
|
|
|
|
panic("unable to read enough random bytes for iv")
|
|
|
|
}
|
2015-04-15 18:51:52 +00:00
|
|
|
return iv
|
2015-03-14 18:53:51 +00:00
|
|
|
}
|
|
|
|
|
2015-03-22 20:03:01 +00:00
|
|
|
type jsonMACKey struct {
|
|
|
|
K []byte `json:"k"`
|
|
|
|
R []byte `json:"r"`
|
|
|
|
}
|
|
|
|
|
2017-06-19 19:12:53 +00:00
|
|
|
// MarshalJSON converts the MACKey to JSON.
|
2015-04-30 16:09:08 +00:00
|
|
|
func (m *MACKey) MarshalJSON() ([]byte, error) {
|
2015-03-22 20:03:01 +00:00
|
|
|
return json.Marshal(jsonMACKey{K: m.K[:], R: m.R[:]})
|
|
|
|
}
|
|
|
|
|
2017-06-19 19:12:53 +00:00
|
|
|
// UnmarshalJSON fills the key m with data from the JSON representation.
|
2015-04-30 16:09:08 +00:00
|
|
|
func (m *MACKey) UnmarshalJSON(data []byte) error {
|
2015-03-22 20:03:01 +00:00
|
|
|
j := jsonMACKey{}
|
|
|
|
err := json.Unmarshal(data, &j)
|
|
|
|
if err != nil {
|
2016-08-29 20:16:58 +00:00
|
|
|
return errors.Wrap(err, "Unmarshal")
|
2015-03-22 20:03:01 +00:00
|
|
|
}
|
|
|
|
copy(m.K[:], j.K)
|
|
|
|
copy(m.R[:], j.R)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-05-01 15:31:57 +00:00
|
|
|
// Valid tests whether the key k is valid (i.e. not zero).
|
2017-05-16 23:39:39 +00:00
|
|
|
func (m *MACKey) Valid() bool {
|
2015-05-01 15:31:57 +00:00
|
|
|
nonzeroK := false
|
2017-05-16 23:39:39 +00:00
|
|
|
for i := 0; i < len(m.K); i++ {
|
|
|
|
if m.K[i] != 0 {
|
2015-05-01 15:31:57 +00:00
|
|
|
nonzeroK = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !nonzeroK {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2017-05-16 23:39:39 +00:00
|
|
|
for i := 0; i < len(m.R); i++ {
|
|
|
|
if m.R[i] != 0 {
|
2015-05-01 15:31:57 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2017-06-19 19:12:53 +00:00
|
|
|
// MarshalJSON converts the EncryptionKey to JSON.
|
2015-04-12 08:53:46 +00:00
|
|
|
func (k *EncryptionKey) MarshalJSON() ([]byte, error) {
|
2015-03-22 20:03:01 +00:00
|
|
|
return json.Marshal(k[:])
|
|
|
|
}
|
|
|
|
|
2017-06-19 19:12:53 +00:00
|
|
|
// UnmarshalJSON fills the key k with data from the JSON representation.
|
2015-04-12 08:53:46 +00:00
|
|
|
func (k *EncryptionKey) UnmarshalJSON(data []byte) error {
|
2015-04-12 07:41:47 +00:00
|
|
|
d := make([]byte, aesKeySize)
|
2015-03-22 20:03:01 +00:00
|
|
|
err := json.Unmarshal(data, &d)
|
|
|
|
if err != nil {
|
2016-08-29 20:16:58 +00:00
|
|
|
return errors.Wrap(err, "Unmarshal")
|
2015-03-22 20:03:01 +00:00
|
|
|
}
|
|
|
|
copy(k[:], d)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-05-01 15:31:57 +00:00
|
|
|
// Valid tests whether the key k is valid (i.e. not zero).
|
|
|
|
func (k *EncryptionKey) Valid() bool {
|
|
|
|
for i := 0; i < len(k); i++ {
|
|
|
|
if k[i] != 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2015-04-19 12:06:55 +00:00
|
|
|
// ErrInvalidCiphertext is returned when trying to encrypt into the slice that
|
|
|
|
// holds the plaintext.
|
|
|
|
var ErrInvalidCiphertext = errors.New("invalid ciphertext, same slice used for plaintext")
|
|
|
|
|
2017-10-28 08:59:55 +00:00
|
|
|
// validNonce checks that nonce is not all zero.
|
|
|
|
func validNonce(nonce []byte) bool {
|
|
|
|
sum := 0
|
|
|
|
for b := range nonce {
|
|
|
|
sum += b
|
|
|
|
}
|
|
|
|
return sum > 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// statically ensure that *Key implements crypto/cipher.AEAD
|
|
|
|
var _ cipher.AEAD = &Key{}
|
|
|
|
|
|
|
|
// NonceSize returns the size of the nonce that must be passed to Seal
|
|
|
|
// and Open.
|
|
|
|
func (k *Key) NonceSize() int {
|
|
|
|
return ivSize
|
|
|
|
}
|
|
|
|
|
|
|
|
// Overhead returns the maximum difference between the lengths of a
|
|
|
|
// plaintext and its ciphertext.
|
|
|
|
func (k *Key) Overhead() int {
|
|
|
|
return macSize
|
|
|
|
}
|
|
|
|
|
|
|
|
// Seal encrypts and authenticates plaintext, authenticates the
|
|
|
|
// additional data and appends the result to dst, returning the updated
|
|
|
|
// slice. The nonce must be NonceSize() bytes long and unique for all
|
|
|
|
// time, for a given key.
|
|
|
|
//
|
|
|
|
// The plaintext and dst may alias exactly or not at all. To reuse
|
|
|
|
// plaintext's storage for the encrypted output, use plaintext[:0] as dst.
|
|
|
|
func (k *Key) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
|
|
|
if !k.Valid() {
|
|
|
|
panic("key is invalid")
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(additionalData) > 0 {
|
|
|
|
panic("additional data is not supported")
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(nonce) != ivSize {
|
|
|
|
panic("incorrect nonce length")
|
|
|
|
}
|
|
|
|
|
|
|
|
if !validNonce(nonce) {
|
|
|
|
panic("nonce is invalid")
|
|
|
|
}
|
|
|
|
|
|
|
|
// extend dst so that the ciphertext fits
|
|
|
|
ciphertextLength := len(plaintext) + k.Overhead()
|
|
|
|
pos := len(dst)
|
|
|
|
|
|
|
|
capacity := cap(dst) - len(dst)
|
|
|
|
if capacity < ciphertextLength {
|
|
|
|
dst = dst[:cap(dst)]
|
|
|
|
dst = append(dst, make([]byte, ciphertextLength-capacity)...)
|
|
|
|
} else {
|
|
|
|
dst = dst[:pos+ciphertextLength]
|
|
|
|
}
|
|
|
|
|
|
|
|
c, err := aes.NewCipher(k.EncryptionKey[:])
|
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Sprintf("unable to create cipher: %v", err))
|
|
|
|
}
|
|
|
|
e := cipher.NewCTR(c, nonce)
|
|
|
|
e.XORKeyStream(dst[pos:pos+len(plaintext)], plaintext)
|
|
|
|
|
|
|
|
// truncate to only cover the ciphertext
|
|
|
|
dst = dst[:pos+len(plaintext)]
|
|
|
|
|
|
|
|
mac := poly1305MAC(dst[pos:], nonce, &k.MACKey)
|
|
|
|
dst = append(dst, mac...)
|
|
|
|
|
|
|
|
return dst
|
|
|
|
}
|
|
|
|
|
|
|
|
// Open decrypts and authenticates ciphertext, authenticates the
|
|
|
|
// additional data and, if successful, appends the resulting plaintext
|
|
|
|
// to dst, returning the updated slice. The nonce must be NonceSize()
|
|
|
|
// bytes long and both it and the additional data must match the
|
|
|
|
// value passed to Seal.
|
|
|
|
//
|
|
|
|
// The ciphertext and dst may alias exactly or not at all. To reuse
|
|
|
|
// ciphertext's storage for the decrypted output, use ciphertext[:0] as dst.
|
|
|
|
//
|
|
|
|
// Even if the function fails, the contents of dst, up to its capacity,
|
|
|
|
// may be overwritten.
|
|
|
|
func (k *Key) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
|
|
|
if !k.Valid() {
|
|
|
|
return nil, errors.New("invalid key")
|
|
|
|
}
|
|
|
|
|
|
|
|
// check parameters
|
|
|
|
if len(nonce) != ivSize {
|
|
|
|
panic("incorrect nonce length")
|
|
|
|
}
|
|
|
|
|
|
|
|
if !validNonce(nonce) {
|
|
|
|
return nil, errors.New("nonce is invalid")
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for plausible length
|
|
|
|
if len(ciphertext) < k.Overhead() {
|
|
|
|
return nil, errors.Errorf("trying to decrypt invalid data: ciphertext too small")
|
|
|
|
}
|
|
|
|
|
|
|
|
// extract mac
|
|
|
|
l := len(ciphertext) - macSize
|
|
|
|
ct, mac := ciphertext[:l], ciphertext[l:]
|
|
|
|
|
|
|
|
// verify mac
|
|
|
|
if !poly1305Verify(ct, nonce, &k.MACKey, mac) {
|
|
|
|
return nil, ErrUnauthenticated
|
|
|
|
}
|
|
|
|
|
|
|
|
// extend dst so that the plaintext fits
|
|
|
|
plaintextLength := len(ct)
|
|
|
|
pos := len(dst)
|
|
|
|
|
|
|
|
capacity := cap(dst) - len(dst)
|
|
|
|
if capacity < plaintextLength {
|
|
|
|
dst = dst[:cap(dst)]
|
|
|
|
dst = append(dst, make([]byte, plaintextLength-capacity)...)
|
|
|
|
} else {
|
|
|
|
dst = dst[:pos+plaintextLength]
|
|
|
|
}
|
|
|
|
|
|
|
|
// decrypt data
|
|
|
|
c, err := aes.NewCipher(k.EncryptionKey[:])
|
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Sprintf("unable to create cipher: %v", err))
|
|
|
|
}
|
|
|
|
e := cipher.NewCTR(c, nonce)
|
|
|
|
e.XORKeyStream(dst[pos:], ct)
|
|
|
|
|
|
|
|
return dst, nil
|
|
|
|
}
|
|
|
|
|
2015-04-30 16:09:08 +00:00
|
|
|
// Encrypt encrypts and authenticates data. Stored in ciphertext is IV || Ciphertext ||
|
2015-04-12 18:58:41 +00:00
|
|
|
// MAC. Encrypt returns the new ciphertext slice, which is extended when
|
2015-04-19 11:34:42 +00:00
|
|
|
// necessary. ciphertext and plaintext may not point to (exactly) the same
|
|
|
|
// slice or non-intersecting slices.
|
2017-06-19 19:12:53 +00:00
|
|
|
func (k *Key) Encrypt(ciphertext []byte, plaintext []byte) ([]byte, error) {
|
|
|
|
if !k.Valid() {
|
2015-11-22 19:42:20 +00:00
|
|
|
return nil, errors.New("invalid key")
|
|
|
|
}
|
|
|
|
|
2015-04-19 11:34:42 +00:00
|
|
|
ciphertext = ciphertext[:cap(ciphertext)]
|
2015-04-19 12:06:55 +00:00
|
|
|
|
|
|
|
// test for same slice, if possible
|
|
|
|
if len(plaintext) > 0 && len(ciphertext) > 0 && &plaintext[0] == &ciphertext[0] {
|
|
|
|
return nil, ErrInvalidCiphertext
|
|
|
|
}
|
|
|
|
|
|
|
|
// extend ciphertext slice if necessary
|
2015-04-19 11:34:42 +00:00
|
|
|
if len(ciphertext) < len(plaintext)+Extension {
|
2017-08-28 17:18:29 +00:00
|
|
|
ext := len(plaintext) + Extension - len(ciphertext)
|
2015-04-12 18:58:41 +00:00
|
|
|
ciphertext = append(ciphertext, make([]byte, ext)...)
|
2015-03-14 18:53:51 +00:00
|
|
|
}
|
|
|
|
|
2017-10-28 08:59:55 +00:00
|
|
|
iv := NewRandomNonce()
|
2017-08-28 17:18:29 +00:00
|
|
|
copy(ciphertext, iv[:])
|
|
|
|
|
2017-06-19 19:12:53 +00:00
|
|
|
c, err := aes.NewCipher(k.EncryptionKey[:])
|
2015-03-14 18:53:51 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Sprintf("unable to create cipher: %v", err))
|
|
|
|
}
|
2017-08-28 17:18:29 +00:00
|
|
|
e := cipher.NewCTR(c, ciphertext[:ivSize])
|
2015-04-19 11:34:42 +00:00
|
|
|
e.XORKeyStream(ciphertext[ivSize:], plaintext)
|
2015-04-30 02:28:34 +00:00
|
|
|
|
|
|
|
// truncate to only cover iv and actual ciphertext
|
2015-03-14 18:53:51 +00:00
|
|
|
ciphertext = ciphertext[:ivSize+len(plaintext)]
|
|
|
|
|
2017-06-19 19:12:53 +00:00
|
|
|
mac := poly1305MAC(ciphertext[ivSize:], ciphertext[:ivSize], &k.MACKey)
|
2015-03-14 18:53:51 +00:00
|
|
|
ciphertext = append(ciphertext, mac...)
|
|
|
|
|
2015-04-12 18:58:41 +00:00
|
|
|
return ciphertext, nil
|
2015-03-14 18:53:51 +00:00
|
|
|
}
|
|
|
|
|
2015-03-22 18:09:30 +00:00
|
|
|
// Decrypt verifies and decrypts the ciphertext. Ciphertext must be in the form
|
2015-04-19 11:34:42 +00:00
|
|
|
// IV || Ciphertext || MAC. plaintext and ciphertext may point to (exactly) the
|
|
|
|
// same slice.
|
2017-06-19 19:12:53 +00:00
|
|
|
func (k *Key) Decrypt(plaintext []byte, ciphertextWithMac []byte) (int, error) {
|
|
|
|
if !k.Valid() {
|
2016-09-03 11:34:04 +00:00
|
|
|
return 0, errors.New("invalid key")
|
2015-11-22 19:42:20 +00:00
|
|
|
}
|
|
|
|
|
2015-03-14 18:53:51 +00:00
|
|
|
// check for plausible length
|
2017-08-28 17:18:29 +00:00
|
|
|
if len(ciphertextWithMac) < Extension {
|
|
|
|
return 0, errors.Errorf("trying to decrypt invalid data: ciphertext too small")
|
2015-03-14 18:53:51 +00:00
|
|
|
}
|
|
|
|
|
2016-09-03 11:34:04 +00:00
|
|
|
// check buffer length for plaintext
|
2017-08-28 17:18:29 +00:00
|
|
|
plaintextLength := len(ciphertextWithMac) - Extension
|
2016-09-03 11:34:04 +00:00
|
|
|
if len(plaintext) < plaintextLength {
|
|
|
|
return 0, errors.Errorf("plaintext buffer too small, %d < %d", len(plaintext), plaintextLength)
|
|
|
|
}
|
|
|
|
|
2015-03-14 18:53:51 +00:00
|
|
|
// extract mac
|
2015-04-30 02:28:34 +00:00
|
|
|
l := len(ciphertextWithMac) - macSize
|
|
|
|
ciphertextWithIV, mac := ciphertextWithMac[:l], ciphertextWithMac[l:]
|
2015-03-14 18:53:51 +00:00
|
|
|
|
2017-08-28 17:18:29 +00:00
|
|
|
// extract iv
|
|
|
|
iv, ciphertext := ciphertextWithIV[:ivSize], ciphertextWithIV[ivSize:]
|
|
|
|
|
2015-03-14 18:53:51 +00:00
|
|
|
// verify mac
|
2017-08-28 17:18:29 +00:00
|
|
|
if !poly1305Verify(ciphertext, iv, &k.MACKey, mac) {
|
2016-09-03 11:34:04 +00:00
|
|
|
return 0, ErrUnauthenticated
|
2015-03-14 18:53:51 +00:00
|
|
|
}
|
|
|
|
|
2016-09-03 11:34:04 +00:00
|
|
|
if len(ciphertext) != plaintextLength {
|
2017-08-28 17:18:29 +00:00
|
|
|
panic("plaintext and ciphertext lengths do not match")
|
2015-05-04 22:07:57 +00:00
|
|
|
}
|
|
|
|
|
2015-03-14 18:53:51 +00:00
|
|
|
// decrypt data
|
2017-06-19 19:12:53 +00:00
|
|
|
c, err := aes.NewCipher(k.EncryptionKey[:])
|
2015-03-14 18:53:51 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Sprintf("unable to create cipher: %v", err))
|
|
|
|
}
|
|
|
|
e := cipher.NewCTR(c, iv)
|
|
|
|
e.XORKeyStream(plaintext, ciphertext)
|
|
|
|
|
2016-09-03 11:34:04 +00:00
|
|
|
return plaintextLength, nil
|
2015-03-14 18:53:51 +00:00
|
|
|
}
|
|
|
|
|
2015-05-01 15:31:57 +00:00
|
|
|
// Valid tests if the key is valid.
|
|
|
|
func (k *Key) Valid() bool {
|
2017-06-19 19:12:53 +00:00
|
|
|
return k.EncryptionKey.Valid() && k.MACKey.Valid()
|
2015-05-01 15:31:57 +00:00
|
|
|
}
|