mirror of
				https://github.com/restic/restic.git
				synced 2025-11-04 07:11:01 +00:00 
			
		
		
		
	
		
			
	
	
		
			422 lines
		
	
	
	
		
			8.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			422 lines
		
	
	
	
		
			8.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								package restic
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"bytes"
							 | 
						||
| 
								 | 
							
									"crypto/aes"
							 | 
						||
| 
								 | 
							
									"crypto/cipher"
							 | 
						||
| 
								 | 
							
									"crypto/rand"
							 | 
						||
| 
								 | 
							
									"fmt"
							 | 
						||
| 
								 | 
							
									"io"
							 | 
						||
| 
								 | 
							
									"io/ioutil"
							 | 
						||
| 
								 | 
							
									"sync"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									"golang.org/x/crypto/poly1305"
							 | 
						||
| 
								 | 
							
									"golang.org/x/crypto/scrypt"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const (
							 | 
						||
| 
								 | 
							
									AESKeySize = 32      // for AES256
							 | 
						||
| 
								 | 
							
									MACKeySize = 16 + 16 // for Poly1305-AES128
							 | 
						||
| 
								 | 
							
									ivSize     = aes.BlockSize
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type AESKey [32]byte
							 | 
						||
| 
								 | 
							
								type MACKey [32]byte
							 | 
						||
| 
								 | 
							
								type IV [ivSize]byte
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 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
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// key is a [32]byte, in the form k||r
							 | 
						||
| 
								 | 
							
								func poly1305_sign(msg []byte, nonce []byte, key *MACKey) []byte {
							 | 
						||
| 
								 | 
							
									// prepare key for low-level poly1305.Sum(): r||n
							 | 
						||
| 
								 | 
							
									var k [32]byte
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// make sure key is masked
							 | 
						||
| 
								 | 
							
									maskKey(key)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// fill in nonce, encrypted with AES and key[:16]
							 | 
						||
| 
								 | 
							
									cipher, err := aes.NewCipher(key[:16])
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										panic(err)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									cipher.Encrypt(k[16:], nonce[:])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// copy r
							 | 
						||
| 
								 | 
							
									copy(k[:16], key[16:])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// save mac in out
							 | 
						||
| 
								 | 
							
									var out [16]byte
							 | 
						||
| 
								 | 
							
									poly1305.Sum(&out, msg, &k)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return out[:]
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// mask poly1305 key
							 | 
						||
| 
								 | 
							
								func maskKey(k *MACKey) {
							 | 
						||
| 
								 | 
							
									if k == nil {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									for i := 0; i < poly1305.TagSize; i++ {
							 | 
						||
| 
								 | 
							
										k[i+16] = k[i+16] & poly1305KeyMask[i]
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// key: k||r
							 | 
						||
| 
								 | 
							
								func poly1305_verify(msg []byte, nonce []byte, key *MACKey, mac []byte) bool {
							 | 
						||
| 
								 | 
							
									// prepare key for low-level poly1305.Sum(): r||n
							 | 
						||
| 
								 | 
							
									var k [32]byte
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// make sure key is masked
							 | 
						||
| 
								 | 
							
									maskKey(key)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// fill in nonce, encrypted with AES and key[:16]
							 | 
						||
| 
								 | 
							
									cipher, err := aes.NewCipher(key[:16])
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										panic(err)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									cipher.Encrypt(k[16:], nonce[:])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// copy r
							 | 
						||
| 
								 | 
							
									copy(k[:16], key[16:])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// copy mac to array
							 | 
						||
| 
								 | 
							
									var m [16]byte
							 | 
						||
| 
								 | 
							
									copy(m[:], mac)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return poly1305.Verify(&m, msg, &k)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func generateRandomAESKey() (k *AESKey) {
							 | 
						||
| 
								 | 
							
									k = &AESKey{}
							 | 
						||
| 
								 | 
							
									n, err := rand.Read(k[:])
							 | 
						||
| 
								 | 
							
									if n != AESKeySize || err != nil {
							 | 
						||
| 
								 | 
							
										panic("unable to read enough random bytes for encryption key")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// returns [32]byte == k||r
							 | 
						||
| 
								 | 
							
								func generateRandomMACKey() (k *MACKey) {
							 | 
						||
| 
								 | 
							
									k = &MACKey{}
							 | 
						||
| 
								 | 
							
									n, err := rand.Read(k[:])
							 | 
						||
| 
								 | 
							
									if n != MACKeySize || err != nil {
							 | 
						||
| 
								 | 
							
										panic("unable to read enough random bytes for mac key")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// mask r in second half
							 | 
						||
| 
								 | 
							
									maskKey(k)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func generateRandomIV() (iv IV) {
							 | 
						||
| 
								 | 
							
									n, err := rand.Read(iv[:])
							 | 
						||
| 
								 | 
							
									if n != ivSize || err != nil {
							 | 
						||
| 
								 | 
							
										panic("unable to read enough random bytes for iv")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Encrypt encrypts and signs data. Stored in ciphertext is IV || Ciphertext ||
							 | 
						||
| 
								 | 
							
								// MAC. Encrypt returns the ciphertext's length.
							 | 
						||
| 
								 | 
							
								func Encrypt(ks *keys, ciphertext, plaintext []byte) (int, error) {
							 | 
						||
| 
								 | 
							
									if cap(ciphertext) < len(plaintext)+ivSize+macSize {
							 | 
						||
| 
								 | 
							
										return 0, ErrBufferTooSmall
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									iv := generateRandomIV()
							 | 
						||
| 
								 | 
							
									copy(ciphertext, iv[:])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									c, err := aes.NewCipher(ks.Encrypt[:])
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										panic(fmt.Sprintf("unable to create cipher: %v", err))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									e := cipher.NewCTR(c, ciphertext[:ivSize])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									e.XORKeyStream(ciphertext[ivSize:cap(ciphertext)], plaintext)
							 | 
						||
| 
								 | 
							
									ciphertext = ciphertext[:ivSize+len(plaintext)]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									mac := poly1305_sign(ciphertext[ivSize:], ciphertext[:ivSize], ks.Sign)
							 | 
						||
| 
								 | 
							
									ciphertext = append(ciphertext, mac...)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return len(ciphertext), nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Decrypt verifes and decrypts the ciphertext. Ciphertext must be in the form
							 | 
						||
| 
								 | 
							
								// IV || Ciphertext || MAC.
							 | 
						||
| 
								 | 
							
								func Decrypt(ks *keys, plaintext, ciphertext []byte) ([]byte, error) {
							 | 
						||
| 
								 | 
							
									// check for plausible length
							 | 
						||
| 
								 | 
							
									if len(ciphertext) < ivSize+macSize {
							 | 
						||
| 
								 | 
							
										panic("trying to decrypt invalid data: ciphertext too small")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if cap(plaintext) < len(ciphertext) {
							 | 
						||
| 
								 | 
							
										// extend plaintext
							 | 
						||
| 
								 | 
							
										plaintext = append(plaintext, make([]byte, len(ciphertext)-cap(plaintext))...)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// extract mac
							 | 
						||
| 
								 | 
							
									l := len(ciphertext) - macSize
							 | 
						||
| 
								 | 
							
									ciphertext, mac := ciphertext[:l], ciphertext[l:]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// verify mac
							 | 
						||
| 
								 | 
							
									if !poly1305_verify(ciphertext[ivSize:], ciphertext[:ivSize], ks.Sign, mac) {
							 | 
						||
| 
								 | 
							
										return nil, ErrUnauthenticated
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// extract iv
							 | 
						||
| 
								 | 
							
									iv, ciphertext := ciphertext[:ivSize], ciphertext[ivSize:]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// decrypt data
							 | 
						||
| 
								 | 
							
									c, err := aes.NewCipher(ks.Encrypt[:])
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										panic(fmt.Sprintf("unable to create cipher: %v", err))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// decrypt
							 | 
						||
| 
								 | 
							
									e := cipher.NewCTR(c, iv)
							 | 
						||
| 
								 | 
							
									plaintext = plaintext[:len(ciphertext)]
							 | 
						||
| 
								 | 
							
									e.XORKeyStream(plaintext, ciphertext)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return plaintext, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// runs scrypt(password)
							 | 
						||
| 
								 | 
							
								func kdf(k *Key, password string) (*keys, error) {
							 | 
						||
| 
								 | 
							
									if len(k.Salt) == 0 {
							 | 
						||
| 
								 | 
							
										return nil, fmt.Errorf("scrypt() called with empty salt")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									keybytes := MACKeySize + AESKeySize
							 | 
						||
| 
								 | 
							
									scryptKeys, err := scrypt.Key([]byte(password), k.Salt, k.N, k.R, k.P, keybytes)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, fmt.Errorf("error deriving keys from password: %v", err)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if len(scryptKeys) != keybytes {
							 | 
						||
| 
								 | 
							
										return nil, fmt.Errorf("invalid numbers of bytes expanded from scrypt(): %d", len(scryptKeys))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									ek := &AESKey{}
							 | 
						||
| 
								 | 
							
									copy(ek[:], scryptKeys[:AESKeySize])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									mk := &MACKey{}
							 | 
						||
| 
								 | 
							
									copy(mk[:], scryptKeys[AESKeySize:])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									ks := &keys{
							 | 
						||
| 
								 | 
							
										Encrypt: ek,
							 | 
						||
| 
								 | 
							
										Sign:    mk,
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return ks, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type encryptWriter struct {
							 | 
						||
| 
								 | 
							
									iv      IV
							 | 
						||
| 
								 | 
							
									wroteIV bool
							 | 
						||
| 
								 | 
							
									data    *bytes.Buffer
							 | 
						||
| 
								 | 
							
									key     *keys
							 | 
						||
| 
								 | 
							
									s       cipher.Stream
							 | 
						||
| 
								 | 
							
									w       io.Writer
							 | 
						||
| 
								 | 
							
									origWr  io.Writer
							 | 
						||
| 
								 | 
							
									err     error // remember error writing iv
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (e *encryptWriter) Close() error {
							 | 
						||
| 
								 | 
							
									// write mac
							 | 
						||
| 
								 | 
							
									mac := poly1305_sign(e.data.Bytes()[ivSize:], e.data.Bytes()[:ivSize], e.key.Sign)
							 | 
						||
| 
								 | 
							
									_, err := e.origWr.Write(mac)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// return buffer
							 | 
						||
| 
								 | 
							
									FreeChunkBuf("EncryptWriter", e.data.Bytes())
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const encryptWriterChunkSize = 512 * 1024 // 512 KiB
							 | 
						||
| 
								 | 
							
								var encryptWriterBufPool = sync.Pool{
							 | 
						||
| 
								 | 
							
									New: func() interface{} {
							 | 
						||
| 
								 | 
							
										return make([]byte, encryptWriterChunkSize)
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (e *encryptWriter) Write(p []byte) (int, error) {
							 | 
						||
| 
								 | 
							
									// write iv first
							 | 
						||
| 
								 | 
							
									if !e.wroteIV {
							 | 
						||
| 
								 | 
							
										_, e.err = e.origWr.Write(e.iv[:])
							 | 
						||
| 
								 | 
							
										e.wroteIV = true
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if e.err != nil {
							 | 
						||
| 
								 | 
							
										return 0, e.err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									buf := encryptWriterBufPool.Get().([]byte)
							 | 
						||
| 
								 | 
							
									defer encryptWriterBufPool.Put(buf)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									written := 0
							 | 
						||
| 
								 | 
							
									for len(p) > 0 {
							 | 
						||
| 
								 | 
							
										max := len(p)
							 | 
						||
| 
								 | 
							
										if max > encryptWriterChunkSize {
							 | 
						||
| 
								 | 
							
											max = encryptWriterChunkSize
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										e.s.XORKeyStream(buf, p[:max])
							 | 
						||
| 
								 | 
							
										n, err := e.w.Write(buf[:max])
							 | 
						||
| 
								 | 
							
										if n != max {
							 | 
						||
| 
								 | 
							
											if err == nil { // should never happen
							 | 
						||
| 
								 | 
							
												err = io.ErrShortWrite
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										written += n
							 | 
						||
| 
								 | 
							
										p = p[n:]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											e.err = err
							 | 
						||
| 
								 | 
							
											return written, err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return written, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// EncryptTo buffers data written to the returned io.WriteCloser. When Close()
							 | 
						||
| 
								 | 
							
								// is called, the data is encrypted an written to the underlying writer.
							 | 
						||
| 
								 | 
							
								func EncryptTo(ks *keys, wr io.Writer) io.WriteCloser {
							 | 
						||
| 
								 | 
							
									ew := &encryptWriter{
							 | 
						||
| 
								 | 
							
										iv:     generateRandomIV(),
							 | 
						||
| 
								 | 
							
										data:   bytes.NewBuffer(GetChunkBuf("EncryptWriter")[:0]),
							 | 
						||
| 
								 | 
							
										key:    ks,
							 | 
						||
| 
								 | 
							
										origWr: wr,
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// buffer iv for mac
							 | 
						||
| 
								 | 
							
									_, err := ew.data.Write(ew.iv[:])
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										panic(err)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									c, err := aes.NewCipher(ks.Encrypt[:])
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										panic(fmt.Sprintf("unable to create cipher: %v", err))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									ew.s = cipher.NewCTR(c, ew.iv[:])
							 | 
						||
| 
								 | 
							
									ew.w = io.MultiWriter(ew.data, wr)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return ew
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type decryptReader struct {
							 | 
						||
| 
								 | 
							
									buf []byte
							 | 
						||
| 
								 | 
							
									pos int
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (d *decryptReader) Read(dst []byte) (int, error) {
							 | 
						||
| 
								 | 
							
									if d.buf == nil {
							 | 
						||
| 
								 | 
							
										return 0, io.EOF
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if len(dst) == 0 {
							 | 
						||
| 
								 | 
							
										return 0, nil
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									remaining := len(d.buf) - d.pos
							 | 
						||
| 
								 | 
							
									if len(dst) >= remaining {
							 | 
						||
| 
								 | 
							
										n := copy(dst, d.buf[d.pos:])
							 | 
						||
| 
								 | 
							
										d.Close()
							 | 
						||
| 
								 | 
							
										return n, io.EOF
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									n := copy(dst, d.buf[d.pos:d.pos+len(dst)])
							 | 
						||
| 
								 | 
							
									d.pos += n
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return n, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (d *decryptReader) ReadByte() (c byte, err error) {
							 | 
						||
| 
								 | 
							
									if d.buf == nil {
							 | 
						||
| 
								 | 
							
										return 0, io.EOF
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									remaining := len(d.buf) - d.pos
							 | 
						||
| 
								 | 
							
									if remaining == 1 {
							 | 
						||
| 
								 | 
							
										c = d.buf[d.pos]
							 | 
						||
| 
								 | 
							
										d.Close()
							 | 
						||
| 
								 | 
							
										return c, io.EOF
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									c = d.buf[d.pos]
							 | 
						||
| 
								 | 
							
									d.pos++
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (d *decryptReader) Close() error {
							 | 
						||
| 
								 | 
							
									if d.buf == nil {
							 | 
						||
| 
								 | 
							
										return nil
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									FreeChunkBuf("decryptReader", d.buf)
							 | 
						||
| 
								 | 
							
									d.buf = nil
							 | 
						||
| 
								 | 
							
									return nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// DecryptFrom verifies and decrypts the ciphertext read from rd with ks and
							 | 
						||
| 
								 | 
							
								// makes it available on the returned Reader. Ciphertext must be in the form IV
							 | 
						||
| 
								 | 
							
								// || Ciphertext || MAC. In order to correctly verify the ciphertext, rd is
							 | 
						||
| 
								 | 
							
								// drained, locally buffered and made available on the returned Reader
							 | 
						||
| 
								 | 
							
								// afterwards. If a MAC verification failure is observed, it is returned
							 | 
						||
| 
								 | 
							
								// immediately.
							 | 
						||
| 
								 | 
							
								func DecryptFrom(ks *keys, rd io.Reader) (io.ReadCloser, error) {
							 | 
						||
| 
								 | 
							
									ciphertext := GetChunkBuf("decryptReader")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									ciphertext = ciphertext[0:cap(ciphertext)]
							 | 
						||
| 
								 | 
							
									n, err := io.ReadFull(rd, ciphertext)
							 | 
						||
| 
								 | 
							
									if err != io.ErrUnexpectedEOF {
							 | 
						||
| 
								 | 
							
										// read remaining data
							 | 
						||
| 
								 | 
							
										buf, e := ioutil.ReadAll(rd)
							 | 
						||
| 
								 | 
							
										ciphertext = append(ciphertext, buf...)
							 | 
						||
| 
								 | 
							
										n += len(buf)
							 | 
						||
| 
								 | 
							
										err = e
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
										err = nil
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									ciphertext = ciphertext[:n]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// decrypt
							 | 
						||
| 
								 | 
							
									ciphertext, err = Decrypt(ks, ciphertext, ciphertext)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return &decryptReader{buf: ciphertext}, nil
							 | 
						||
| 
								 | 
							
								}
							 |