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 }