github.com/artpar/rclone@v1.67.3/backend/crypt/cipher.go (about)

     1  package crypt
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"crypto/aes"
     7  	gocipher "crypto/cipher"
     8  	"crypto/rand"
     9  	"encoding/base32"
    10  	"encoding/base64"
    11  	"errors"
    12  	"fmt"
    13  	"io"
    14  	"strconv"
    15  	"strings"
    16  	"sync"
    17  	"time"
    18  	"unicode/utf8"
    19  
    20  	"github.com/Max-Sum/base32768"
    21  	"github.com/artpar/rclone/backend/crypt/pkcs7"
    22  	"github.com/artpar/rclone/fs"
    23  	"github.com/artpar/rclone/fs/accounting"
    24  	"github.com/artpar/rclone/lib/readers"
    25  	"github.com/artpar/rclone/lib/version"
    26  	"github.com/rfjakob/eme"
    27  	"golang.org/x/crypto/nacl/secretbox"
    28  	"golang.org/x/crypto/scrypt"
    29  )
    30  
    31  // Constants
    32  const (
    33  	nameCipherBlockSize = aes.BlockSize
    34  	fileMagic           = "RCLONE\x00\x00"
    35  	fileMagicSize       = len(fileMagic)
    36  	fileNonceSize       = 24
    37  	fileHeaderSize      = fileMagicSize + fileNonceSize
    38  	blockHeaderSize     = secretbox.Overhead
    39  	blockDataSize       = 64 * 1024
    40  	blockSize           = blockHeaderSize + blockDataSize
    41  )
    42  
    43  // Errors returned by cipher
    44  var (
    45  	ErrorBadDecryptUTF8          = errors.New("bad decryption - utf-8 invalid")
    46  	ErrorBadDecryptControlChar   = errors.New("bad decryption - contains control chars")
    47  	ErrorNotAMultipleOfBlocksize = errors.New("not a multiple of blocksize")
    48  	ErrorTooShortAfterDecode     = errors.New("too short after base32 decode")
    49  	ErrorTooLongAfterDecode      = errors.New("too long after base32 decode")
    50  	ErrorEncryptedFileTooShort   = errors.New("file is too short to be encrypted")
    51  	ErrorEncryptedFileBadHeader  = errors.New("file has truncated block header")
    52  	ErrorEncryptedBadMagic       = errors.New("not an encrypted file - bad magic string")
    53  	ErrorEncryptedBadBlock       = errors.New("failed to authenticate decrypted block - bad password?")
    54  	ErrorBadBase32Encoding       = errors.New("bad base32 filename encoding")
    55  	ErrorFileClosed              = errors.New("file already closed")
    56  	ErrorNotAnEncryptedFile      = errors.New("not an encrypted file - does not match suffix")
    57  	ErrorBadSeek                 = errors.New("Seek beyond end of file")
    58  	ErrorSuffixMissingDot        = errors.New("suffix config setting should include a '.'")
    59  	defaultSalt                  = []byte{0xA8, 0x0D, 0xF4, 0x3A, 0x8F, 0xBD, 0x03, 0x08, 0xA7, 0xCA, 0xB8, 0x3E, 0x58, 0x1F, 0x86, 0xB1}
    60  	obfuscQuoteRune              = '!'
    61  )
    62  
    63  // Global variables
    64  var (
    65  	fileMagicBytes = []byte(fileMagic)
    66  )
    67  
    68  // ReadSeekCloser is the interface of the read handles
    69  type ReadSeekCloser interface {
    70  	io.Reader
    71  	io.Seeker
    72  	io.Closer
    73  	fs.RangeSeeker
    74  }
    75  
    76  // OpenRangeSeek opens the file handle at the offset with the limit given
    77  type OpenRangeSeek func(ctx context.Context, offset, limit int64) (io.ReadCloser, error)
    78  
    79  // NameEncryptionMode is the type of file name encryption in use
    80  type NameEncryptionMode int
    81  
    82  // NameEncryptionMode levels
    83  const (
    84  	NameEncryptionOff NameEncryptionMode = iota
    85  	NameEncryptionStandard
    86  	NameEncryptionObfuscated
    87  )
    88  
    89  // NewNameEncryptionMode turns a string into a NameEncryptionMode
    90  func NewNameEncryptionMode(s string) (mode NameEncryptionMode, err error) {
    91  	s = strings.ToLower(s)
    92  	switch s {
    93  	case "off":
    94  		mode = NameEncryptionOff
    95  	case "standard":
    96  		mode = NameEncryptionStandard
    97  	case "obfuscate":
    98  		mode = NameEncryptionObfuscated
    99  	default:
   100  		err = fmt.Errorf("unknown file name encryption mode %q", s)
   101  	}
   102  	return mode, err
   103  }
   104  
   105  // String turns mode into a human-readable string
   106  func (mode NameEncryptionMode) String() (out string) {
   107  	switch mode {
   108  	case NameEncryptionOff:
   109  		out = "off"
   110  	case NameEncryptionStandard:
   111  		out = "standard"
   112  	case NameEncryptionObfuscated:
   113  		out = "obfuscate"
   114  	default:
   115  		out = fmt.Sprintf("Unknown mode #%d", mode)
   116  	}
   117  	return out
   118  }
   119  
   120  // fileNameEncoding are the encoding methods dealing with encrypted file names
   121  type fileNameEncoding interface {
   122  	EncodeToString(src []byte) string
   123  	DecodeString(s string) ([]byte, error)
   124  }
   125  
   126  // caseInsensitiveBase32Encoding defines a file name encoding
   127  // using a modified version of standard base32 as described in
   128  // RFC4648
   129  //
   130  // The standard encoding is modified in two ways
   131  //   - it becomes lower case (no-one likes upper case filenames!)
   132  //   - we strip the padding character `=`
   133  type caseInsensitiveBase32Encoding struct{}
   134  
   135  // EncodeToString encodes a string using the modified version of
   136  // base32 encoding.
   137  func (caseInsensitiveBase32Encoding) EncodeToString(src []byte) string {
   138  	encoded := base32.HexEncoding.EncodeToString(src)
   139  	encoded = strings.TrimRight(encoded, "=")
   140  	return strings.ToLower(encoded)
   141  }
   142  
   143  // DecodeString decodes a string as encoded by EncodeToString
   144  func (caseInsensitiveBase32Encoding) DecodeString(s string) ([]byte, error) {
   145  	if strings.HasSuffix(s, "=") {
   146  		return nil, ErrorBadBase32Encoding
   147  	}
   148  	// First figure out how many padding characters to add
   149  	roundUpToMultipleOf8 := (len(s) + 7) &^ 7
   150  	equals := roundUpToMultipleOf8 - len(s)
   151  	s = strings.ToUpper(s) + "========"[:equals]
   152  	return base32.HexEncoding.DecodeString(s)
   153  }
   154  
   155  // NewNameEncoding creates a NameEncoding from a string
   156  func NewNameEncoding(s string) (enc fileNameEncoding, err error) {
   157  	s = strings.ToLower(s)
   158  	switch s {
   159  	case "base32":
   160  		enc = caseInsensitiveBase32Encoding{}
   161  	case "base64":
   162  		enc = base64.RawURLEncoding
   163  	case "base32768":
   164  		enc = base32768.SafeEncoding
   165  	default:
   166  		err = fmt.Errorf("unknown file name encoding mode %q", s)
   167  	}
   168  	return enc, err
   169  }
   170  
   171  // Cipher defines an encoding and decoding cipher for the crypt backend
   172  type Cipher struct {
   173  	dataKey         [32]byte                  // Key for secretbox
   174  	nameKey         [32]byte                  // 16,24 or 32 bytes
   175  	nameTweak       [nameCipherBlockSize]byte // used to tweak the name crypto
   176  	block           gocipher.Block
   177  	mode            NameEncryptionMode
   178  	fileNameEnc     fileNameEncoding
   179  	buffers         sync.Pool // encrypt/decrypt buffers
   180  	cryptoRand      io.Reader // read crypto random numbers from here
   181  	dirNameEncrypt  bool
   182  	passBadBlocks   bool // if set passed bad blocks as zeroed blocks
   183  	encryptedSuffix string
   184  }
   185  
   186  // newCipher initialises the cipher.  If salt is "" then it uses a built in salt val
   187  func newCipher(mode NameEncryptionMode, password, salt string, dirNameEncrypt bool, enc fileNameEncoding) (*Cipher, error) {
   188  	c := &Cipher{
   189  		mode:            mode,
   190  		fileNameEnc:     enc,
   191  		cryptoRand:      rand.Reader,
   192  		dirNameEncrypt:  dirNameEncrypt,
   193  		encryptedSuffix: ".bin",
   194  	}
   195  	c.buffers.New = func() interface{} {
   196  		return new([blockSize]byte)
   197  	}
   198  	err := c.Key(password, salt)
   199  	if err != nil {
   200  		return nil, err
   201  	}
   202  	return c, nil
   203  }
   204  
   205  // setEncryptedSuffix set suffix, or an empty string
   206  func (c *Cipher) setEncryptedSuffix(suffix string) {
   207  	if strings.EqualFold(suffix, "none") {
   208  		c.encryptedSuffix = ""
   209  		return
   210  	}
   211  	if !strings.HasPrefix(suffix, ".") {
   212  		fs.Errorf(nil, "crypt: bad suffix: %v", ErrorSuffixMissingDot)
   213  		suffix = "." + suffix
   214  	}
   215  	c.encryptedSuffix = suffix
   216  }
   217  
   218  // Call to set bad block pass through
   219  func (c *Cipher) setPassBadBlocks(passBadBlocks bool) {
   220  	c.passBadBlocks = passBadBlocks
   221  }
   222  
   223  // Key creates all the internal keys from the password passed in using
   224  // scrypt.
   225  //
   226  // If salt is "" we use a fixed salt just to make attackers lives
   227  // slightly harder than using no salt.
   228  //
   229  // Note that empty password makes all 0x00 keys which is used in the
   230  // tests.
   231  func (c *Cipher) Key(password, salt string) (err error) {
   232  	const keySize = len(c.dataKey) + len(c.nameKey) + len(c.nameTweak)
   233  	var saltBytes = defaultSalt
   234  	if salt != "" {
   235  		saltBytes = []byte(salt)
   236  	}
   237  	var key []byte
   238  	if password == "" {
   239  		key = make([]byte, keySize)
   240  	} else {
   241  		key, err = scrypt.Key([]byte(password), saltBytes, 16384, 8, 1, keySize)
   242  		if err != nil {
   243  			return err
   244  		}
   245  	}
   246  	copy(c.dataKey[:], key)
   247  	copy(c.nameKey[:], key[len(c.dataKey):])
   248  	copy(c.nameTweak[:], key[len(c.dataKey)+len(c.nameKey):])
   249  	// Key the name cipher
   250  	c.block, err = aes.NewCipher(c.nameKey[:])
   251  	return err
   252  }
   253  
   254  // getBlock gets a block from the pool of size blockSize
   255  func (c *Cipher) getBlock() *[blockSize]byte {
   256  	return c.buffers.Get().(*[blockSize]byte)
   257  }
   258  
   259  // putBlock returns a block to the pool of size blockSize
   260  func (c *Cipher) putBlock(buf *[blockSize]byte) {
   261  	c.buffers.Put(buf)
   262  }
   263  
   264  // encryptSegment encrypts a path segment
   265  //
   266  // This uses EME with AES.
   267  //
   268  // EME (ECB-Mix-ECB) is a wide-block encryption mode presented in the
   269  // 2003 paper "A Parallelizable Enciphering Mode" by Halevi and
   270  // Rogaway.
   271  //
   272  // This makes for deterministic encryption which is what we want - the
   273  // same filename must encrypt to the same thing.
   274  //
   275  // This means that
   276  //   - filenames with the same name will encrypt the same
   277  //   - filenames which start the same won't have a common prefix
   278  func (c *Cipher) encryptSegment(plaintext string) string {
   279  	if plaintext == "" {
   280  		return ""
   281  	}
   282  	paddedPlaintext := pkcs7.Pad(nameCipherBlockSize, []byte(plaintext))
   283  	ciphertext := eme.Transform(c.block, c.nameTweak[:], paddedPlaintext, eme.DirectionEncrypt)
   284  	return c.fileNameEnc.EncodeToString(ciphertext)
   285  }
   286  
   287  // decryptSegment decrypts a path segment
   288  func (c *Cipher) decryptSegment(ciphertext string) (string, error) {
   289  	if ciphertext == "" {
   290  		return "", nil
   291  	}
   292  	rawCiphertext, err := c.fileNameEnc.DecodeString(ciphertext)
   293  	if err != nil {
   294  		return "", err
   295  	}
   296  	if len(rawCiphertext)%nameCipherBlockSize != 0 {
   297  		return "", ErrorNotAMultipleOfBlocksize
   298  	}
   299  	if len(rawCiphertext) == 0 {
   300  		// not possible if decodeFilename() working correctly
   301  		return "", ErrorTooShortAfterDecode
   302  	}
   303  	if len(rawCiphertext) > 2048 {
   304  		return "", ErrorTooLongAfterDecode
   305  	}
   306  	paddedPlaintext := eme.Transform(c.block, c.nameTweak[:], rawCiphertext, eme.DirectionDecrypt)
   307  	plaintext, err := pkcs7.Unpad(nameCipherBlockSize, paddedPlaintext)
   308  	if err != nil {
   309  		return "", err
   310  	}
   311  	return string(plaintext), err
   312  }
   313  
   314  // Simple obfuscation routines
   315  func (c *Cipher) obfuscateSegment(plaintext string) string {
   316  	if plaintext == "" {
   317  		return ""
   318  	}
   319  
   320  	// If the string isn't valid UTF8 then don't rotate; just
   321  	// prepend a !.
   322  	if !utf8.ValidString(plaintext) {
   323  		return "!." + plaintext
   324  	}
   325  
   326  	// Calculate a simple rotation based on the filename and
   327  	// the nameKey
   328  	var dir int
   329  	for _, runeValue := range plaintext {
   330  		dir += int(runeValue)
   331  	}
   332  	dir = dir % 256
   333  
   334  	// We'll use this number to store in the result filename...
   335  	var result bytes.Buffer
   336  	_, _ = result.WriteString(strconv.Itoa(dir) + ".")
   337  
   338  	// but we'll augment it with the nameKey for real calculation
   339  	for i := 0; i < len(c.nameKey); i++ {
   340  		dir += int(c.nameKey[i])
   341  	}
   342  
   343  	// Now for each character, depending on the range it is in
   344  	// we will actually rotate a different amount
   345  	for _, runeValue := range plaintext {
   346  		switch {
   347  		case runeValue == obfuscQuoteRune:
   348  			// Quote the Quote character
   349  			_, _ = result.WriteRune(obfuscQuoteRune)
   350  			_, _ = result.WriteRune(obfuscQuoteRune)
   351  
   352  		case runeValue >= '0' && runeValue <= '9':
   353  			// Number
   354  			thisdir := (dir % 9) + 1
   355  			newRune := '0' + (int(runeValue)-'0'+thisdir)%10
   356  			_, _ = result.WriteRune(rune(newRune))
   357  
   358  		case (runeValue >= 'A' && runeValue <= 'Z') ||
   359  			(runeValue >= 'a' && runeValue <= 'z'):
   360  			// ASCII letter.  Try to avoid trivial A->a mappings
   361  			thisdir := dir%25 + 1
   362  			// Calculate the offset of this character in A-Za-z
   363  			pos := int(runeValue - 'A')
   364  			if pos >= 26 {
   365  				pos -= 6 // It's lower case
   366  			}
   367  			// Rotate the character to the new location
   368  			pos = (pos + thisdir) % 52
   369  			if pos >= 26 {
   370  				pos += 6 // and handle lower case offset again
   371  			}
   372  			_, _ = result.WriteRune(rune('A' + pos))
   373  
   374  		case runeValue >= 0xA0 && runeValue <= 0xFF:
   375  			// Latin 1 supplement
   376  			thisdir := (dir % 95) + 1
   377  			newRune := 0xA0 + (int(runeValue)-0xA0+thisdir)%96
   378  			_, _ = result.WriteRune(rune(newRune))
   379  
   380  		case runeValue >= 0x100:
   381  			// Some random Unicode range; we have no good rules here
   382  			thisdir := (dir % 127) + 1
   383  			base := int(runeValue - runeValue%256)
   384  			newRune := rune(base + (int(runeValue)-base+thisdir)%256)
   385  			// If the new character isn't a valid UTF8 char
   386  			// then don't rotate it.  Quote it instead
   387  			if !utf8.ValidRune(newRune) {
   388  				_, _ = result.WriteRune(obfuscQuoteRune)
   389  				_, _ = result.WriteRune(runeValue)
   390  			} else {
   391  				_, _ = result.WriteRune(newRune)
   392  			}
   393  
   394  		default:
   395  			// Leave character untouched
   396  			_, _ = result.WriteRune(runeValue)
   397  		}
   398  	}
   399  	return result.String()
   400  }
   401  
   402  func (c *Cipher) deobfuscateSegment(ciphertext string) (string, error) {
   403  	if ciphertext == "" {
   404  		return "", nil
   405  	}
   406  	pos := strings.Index(ciphertext, ".")
   407  	if pos == -1 {
   408  		return "", ErrorNotAnEncryptedFile
   409  	} // No .
   410  	num := ciphertext[:pos]
   411  	if num == "!" {
   412  		// No rotation; probably original was not valid unicode
   413  		return ciphertext[pos+1:], nil
   414  	}
   415  	dir, err := strconv.Atoi(num)
   416  	if err != nil {
   417  		return "", ErrorNotAnEncryptedFile // Not a number
   418  	}
   419  
   420  	// add the nameKey to get the real rotate distance
   421  	for i := 0; i < len(c.nameKey); i++ {
   422  		dir += int(c.nameKey[i])
   423  	}
   424  
   425  	var result bytes.Buffer
   426  
   427  	inQuote := false
   428  	for _, runeValue := range ciphertext[pos+1:] {
   429  		switch {
   430  		case inQuote:
   431  			_, _ = result.WriteRune(runeValue)
   432  			inQuote = false
   433  
   434  		case runeValue == obfuscQuoteRune:
   435  			inQuote = true
   436  
   437  		case runeValue >= '0' && runeValue <= '9':
   438  			// Number
   439  			thisdir := (dir % 9) + 1
   440  			newRune := '0' + int(runeValue) - '0' - thisdir
   441  			if newRune < '0' {
   442  				newRune += 10
   443  			}
   444  			_, _ = result.WriteRune(rune(newRune))
   445  
   446  		case (runeValue >= 'A' && runeValue <= 'Z') ||
   447  			(runeValue >= 'a' && runeValue <= 'z'):
   448  			thisdir := dir%25 + 1
   449  			pos := int(runeValue - 'A')
   450  			if pos >= 26 {
   451  				pos -= 6
   452  			}
   453  			pos = pos - thisdir
   454  			if pos < 0 {
   455  				pos += 52
   456  			}
   457  			if pos >= 26 {
   458  				pos += 6
   459  			}
   460  			_, _ = result.WriteRune(rune('A' + pos))
   461  
   462  		case runeValue >= 0xA0 && runeValue <= 0xFF:
   463  			thisdir := (dir % 95) + 1
   464  			newRune := 0xA0 + int(runeValue) - 0xA0 - thisdir
   465  			if newRune < 0xA0 {
   466  				newRune += 96
   467  			}
   468  			_, _ = result.WriteRune(rune(newRune))
   469  
   470  		case runeValue >= 0x100:
   471  			thisdir := (dir % 127) + 1
   472  			base := int(runeValue - runeValue%256)
   473  			newRune := rune(base + (int(runeValue) - base - thisdir))
   474  			if int(newRune) < base {
   475  				newRune += 256
   476  			}
   477  			_, _ = result.WriteRune(newRune)
   478  
   479  		default:
   480  			_, _ = result.WriteRune(runeValue)
   481  
   482  		}
   483  	}
   484  
   485  	return result.String(), nil
   486  }
   487  
   488  // encryptFileName encrypts a file path
   489  func (c *Cipher) encryptFileName(in string) string {
   490  	segments := strings.Split(in, "/")
   491  	for i := range segments {
   492  		// Skip directory name encryption if the user chose to
   493  		// leave them intact
   494  		if !c.dirNameEncrypt && i != (len(segments)-1) {
   495  			continue
   496  		}
   497  
   498  		// Strip version string so that only the non-versioned part
   499  		// of the file name gets encrypted/obfuscated
   500  		hasVersion := false
   501  		var t time.Time
   502  		if i == (len(segments)-1) && version.Match(segments[i]) {
   503  			var s string
   504  			t, s = version.Remove(segments[i])
   505  			// version.Remove can fail, in which case it returns segments[i]
   506  			if s != segments[i] {
   507  				segments[i] = s
   508  				hasVersion = true
   509  			}
   510  		}
   511  
   512  		if c.mode == NameEncryptionStandard {
   513  			segments[i] = c.encryptSegment(segments[i])
   514  		} else {
   515  			segments[i] = c.obfuscateSegment(segments[i])
   516  		}
   517  
   518  		// Add back a version to the encrypted/obfuscated
   519  		// file name, if we stripped it off earlier
   520  		if hasVersion {
   521  			segments[i] = version.Add(segments[i], t)
   522  		}
   523  	}
   524  	return strings.Join(segments, "/")
   525  }
   526  
   527  // EncryptFileName encrypts a file path
   528  func (c *Cipher) EncryptFileName(in string) string {
   529  	if c.mode == NameEncryptionOff {
   530  		return in + c.encryptedSuffix
   531  	}
   532  	return c.encryptFileName(in)
   533  }
   534  
   535  // EncryptDirName encrypts a directory path
   536  func (c *Cipher) EncryptDirName(in string) string {
   537  	if c.mode == NameEncryptionOff || !c.dirNameEncrypt {
   538  		return in
   539  	}
   540  	return c.encryptFileName(in)
   541  }
   542  
   543  // decryptFileName decrypts a file path
   544  func (c *Cipher) decryptFileName(in string) (string, error) {
   545  	segments := strings.Split(in, "/")
   546  	for i := range segments {
   547  		var err error
   548  		// Skip directory name decryption if the user chose to
   549  		// leave them intact
   550  		if !c.dirNameEncrypt && i != (len(segments)-1) {
   551  			continue
   552  		}
   553  
   554  		// Strip version string so that only the non-versioned part
   555  		// of the file name gets decrypted/deobfuscated
   556  		hasVersion := false
   557  		var t time.Time
   558  		if i == (len(segments)-1) && version.Match(segments[i]) {
   559  			var s string
   560  			t, s = version.Remove(segments[i])
   561  			// version.Remove can fail, in which case it returns segments[i]
   562  			if s != segments[i] {
   563  				segments[i] = s
   564  				hasVersion = true
   565  			}
   566  		}
   567  
   568  		if c.mode == NameEncryptionStandard {
   569  			segments[i], err = c.decryptSegment(segments[i])
   570  		} else {
   571  			segments[i], err = c.deobfuscateSegment(segments[i])
   572  		}
   573  
   574  		if err != nil {
   575  			return "", err
   576  		}
   577  
   578  		// Add back a version to the decrypted/deobfuscated
   579  		// file name, if we stripped it off earlier
   580  		if hasVersion {
   581  			segments[i] = version.Add(segments[i], t)
   582  		}
   583  	}
   584  	return strings.Join(segments, "/"), nil
   585  }
   586  
   587  // DecryptFileName decrypts a file path
   588  func (c *Cipher) DecryptFileName(in string) (string, error) {
   589  	if c.mode == NameEncryptionOff {
   590  		remainingLength := len(in) - len(c.encryptedSuffix)
   591  		if remainingLength == 0 || !strings.HasSuffix(in, c.encryptedSuffix) {
   592  			return "", ErrorNotAnEncryptedFile
   593  		}
   594  		decrypted := in[:remainingLength]
   595  		if version.Match(decrypted) {
   596  			_, unversioned := version.Remove(decrypted)
   597  			if unversioned == "" {
   598  				return "", ErrorNotAnEncryptedFile
   599  			}
   600  		}
   601  		// Leave the version string on, if it was there
   602  		return decrypted, nil
   603  	}
   604  	return c.decryptFileName(in)
   605  }
   606  
   607  // DecryptDirName decrypts a directory path
   608  func (c *Cipher) DecryptDirName(in string) (string, error) {
   609  	if c.mode == NameEncryptionOff || !c.dirNameEncrypt {
   610  		return in, nil
   611  	}
   612  	return c.decryptFileName(in)
   613  }
   614  
   615  // NameEncryptionMode returns the encryption mode in use for names
   616  func (c *Cipher) NameEncryptionMode() NameEncryptionMode {
   617  	return c.mode
   618  }
   619  
   620  // nonce is an NACL secretbox nonce
   621  type nonce [fileNonceSize]byte
   622  
   623  // pointer returns the nonce as a *[24]byte for secretbox
   624  func (n *nonce) pointer() *[fileNonceSize]byte {
   625  	return (*[fileNonceSize]byte)(n)
   626  }
   627  
   628  // fromReader fills the nonce from an io.Reader - normally the OSes
   629  // crypto random number generator
   630  func (n *nonce) fromReader(in io.Reader) error {
   631  	read, err := readers.ReadFill(in, (*n)[:])
   632  	if read != fileNonceSize {
   633  		return fmt.Errorf("short read of nonce: %w", err)
   634  	}
   635  	return nil
   636  }
   637  
   638  // fromBuf fills the nonce from the buffer passed in
   639  func (n *nonce) fromBuf(buf []byte) {
   640  	read := copy((*n)[:], buf)
   641  	if read != fileNonceSize {
   642  		panic("buffer to short to read nonce")
   643  	}
   644  }
   645  
   646  // carry 1 up the nonce from position i
   647  func (n *nonce) carry(i int) {
   648  	for ; i < len(*n); i++ {
   649  		digit := (*n)[i]
   650  		newDigit := digit + 1
   651  		(*n)[i] = newDigit
   652  		if newDigit >= digit {
   653  			// exit if no carry
   654  			break
   655  		}
   656  	}
   657  }
   658  
   659  // increment to add 1 to the nonce
   660  func (n *nonce) increment() {
   661  	n.carry(0)
   662  }
   663  
   664  // add a uint64 to the nonce
   665  func (n *nonce) add(x uint64) {
   666  	carry := uint16(0)
   667  	for i := 0; i < 8; i++ {
   668  		digit := (*n)[i]
   669  		xDigit := byte(x)
   670  		x >>= 8
   671  		carry += uint16(digit) + uint16(xDigit)
   672  		(*n)[i] = byte(carry)
   673  		carry >>= 8
   674  	}
   675  	if carry != 0 {
   676  		n.carry(8)
   677  	}
   678  }
   679  
   680  // encrypter encrypts an io.Reader on the fly
   681  type encrypter struct {
   682  	mu       sync.Mutex
   683  	in       io.Reader
   684  	c        *Cipher
   685  	nonce    nonce
   686  	buf      *[blockSize]byte
   687  	readBuf  *[blockSize]byte
   688  	bufIndex int
   689  	bufSize  int
   690  	err      error
   691  }
   692  
   693  // newEncrypter creates a new file handle encrypting on the fly
   694  func (c *Cipher) newEncrypter(in io.Reader, nonce *nonce) (*encrypter, error) {
   695  	fh := &encrypter{
   696  		in:      in,
   697  		c:       c,
   698  		buf:     c.getBlock(),
   699  		readBuf: c.getBlock(),
   700  		bufSize: fileHeaderSize,
   701  	}
   702  	// Initialise nonce
   703  	if nonce != nil {
   704  		fh.nonce = *nonce
   705  	} else {
   706  		err := fh.nonce.fromReader(c.cryptoRand)
   707  		if err != nil {
   708  			return nil, err
   709  		}
   710  	}
   711  	// Copy magic into buffer
   712  	copy((*fh.buf)[:], fileMagicBytes)
   713  	// Copy nonce into buffer
   714  	copy((*fh.buf)[fileMagicSize:], fh.nonce[:])
   715  	return fh, nil
   716  }
   717  
   718  // Read as per io.Reader
   719  func (fh *encrypter) Read(p []byte) (n int, err error) {
   720  	fh.mu.Lock()
   721  	defer fh.mu.Unlock()
   722  
   723  	if fh.err != nil {
   724  		return 0, fh.err
   725  	}
   726  	if fh.bufIndex >= fh.bufSize {
   727  		// Read data
   728  		// FIXME should overlap the reads with a go-routine and 2 buffers?
   729  		readBuf := (*fh.readBuf)[:blockDataSize]
   730  		n, err = readers.ReadFill(fh.in, readBuf)
   731  		if n == 0 {
   732  			return fh.finish(err)
   733  		}
   734  		// possibly err != nil here, but we will process the
   735  		// data and the next call to ReadFill will return 0, err
   736  		// Encrypt the block using the nonce
   737  		secretbox.Seal((*fh.buf)[:0], readBuf[:n], fh.nonce.pointer(), &fh.c.dataKey)
   738  		fh.bufIndex = 0
   739  		fh.bufSize = blockHeaderSize + n
   740  		fh.nonce.increment()
   741  	}
   742  	n = copy(p, (*fh.buf)[fh.bufIndex:fh.bufSize])
   743  	fh.bufIndex += n
   744  	return n, nil
   745  }
   746  
   747  // finish sets the final error and tidies up
   748  func (fh *encrypter) finish(err error) (int, error) {
   749  	if fh.err != nil {
   750  		return 0, fh.err
   751  	}
   752  	fh.err = err
   753  	fh.c.putBlock(fh.buf)
   754  	fh.buf = nil
   755  	fh.c.putBlock(fh.readBuf)
   756  	fh.readBuf = nil
   757  	return 0, err
   758  }
   759  
   760  // Encrypt data encrypts the data stream
   761  func (c *Cipher) encryptData(in io.Reader) (io.Reader, *encrypter, error) {
   762  	in, wrap := accounting.UnWrap(in) // unwrap the accounting off the Reader
   763  	out, err := c.newEncrypter(in, nil)
   764  	if err != nil {
   765  		return nil, nil, err
   766  	}
   767  	return wrap(out), out, nil // and wrap the accounting back on
   768  }
   769  
   770  // EncryptData encrypts the data stream
   771  func (c *Cipher) EncryptData(in io.Reader) (io.Reader, error) {
   772  	out, _, err := c.encryptData(in)
   773  	return out, err
   774  }
   775  
   776  // decrypter decrypts an io.ReaderCloser on the fly
   777  type decrypter struct {
   778  	mu           sync.Mutex
   779  	rc           io.ReadCloser
   780  	nonce        nonce
   781  	initialNonce nonce
   782  	c            *Cipher
   783  	buf          *[blockSize]byte
   784  	readBuf      *[blockSize]byte
   785  	bufIndex     int
   786  	bufSize      int
   787  	err          error
   788  	limit        int64 // limit of bytes to read, -1 for unlimited
   789  	open         OpenRangeSeek
   790  }
   791  
   792  // newDecrypter creates a new file handle decrypting on the fly
   793  func (c *Cipher) newDecrypter(rc io.ReadCloser) (*decrypter, error) {
   794  	fh := &decrypter{
   795  		rc:      rc,
   796  		c:       c,
   797  		buf:     c.getBlock(),
   798  		readBuf: c.getBlock(),
   799  		limit:   -1,
   800  	}
   801  	// Read file header (magic + nonce)
   802  	readBuf := (*fh.readBuf)[:fileHeaderSize]
   803  	n, err := readers.ReadFill(fh.rc, readBuf)
   804  	if n < fileHeaderSize && err == io.EOF {
   805  		// This read from 0..fileHeaderSize-1 bytes
   806  		return nil, fh.finishAndClose(ErrorEncryptedFileTooShort)
   807  	} else if err != io.EOF && err != nil {
   808  		return nil, fh.finishAndClose(err)
   809  	}
   810  	// check the magic
   811  	if !bytes.Equal(readBuf[:fileMagicSize], fileMagicBytes) {
   812  		return nil, fh.finishAndClose(ErrorEncryptedBadMagic)
   813  	}
   814  	// retrieve the nonce
   815  	fh.nonce.fromBuf(readBuf[fileMagicSize:])
   816  	fh.initialNonce = fh.nonce
   817  	return fh, nil
   818  }
   819  
   820  // newDecrypterSeek creates a new file handle decrypting on the fly
   821  func (c *Cipher) newDecrypterSeek(ctx context.Context, open OpenRangeSeek, offset, limit int64) (fh *decrypter, err error) {
   822  	var rc io.ReadCloser
   823  	doRangeSeek := false
   824  	setLimit := false
   825  	// Open initially with no seek
   826  	if offset == 0 && limit < 0 {
   827  		// If no offset or limit then open whole file
   828  		rc, err = open(ctx, 0, -1)
   829  	} else if offset == 0 {
   830  		// If no offset open the header + limit worth of the file
   831  		_, underlyingLimit, _, _ := calculateUnderlying(offset, limit)
   832  		rc, err = open(ctx, 0, int64(fileHeaderSize)+underlyingLimit)
   833  		setLimit = true
   834  	} else {
   835  		// Otherwise just read the header to start with
   836  		rc, err = open(ctx, 0, int64(fileHeaderSize))
   837  		doRangeSeek = true
   838  	}
   839  	if err != nil {
   840  		return nil, err
   841  	}
   842  	// Open the stream which fills in the nonce
   843  	fh, err = c.newDecrypter(rc)
   844  	if err != nil {
   845  		return nil, err
   846  	}
   847  	fh.open = open // will be called by fh.RangeSeek
   848  	if doRangeSeek {
   849  		_, err = fh.RangeSeek(ctx, offset, io.SeekStart, limit)
   850  		if err != nil {
   851  			_ = fh.Close()
   852  			return nil, err
   853  		}
   854  	}
   855  	if setLimit {
   856  		fh.limit = limit
   857  	}
   858  	return fh, nil
   859  }
   860  
   861  // read data into internal buffer - call with fh.mu held
   862  func (fh *decrypter) fillBuffer() (err error) {
   863  	// FIXME should overlap the reads with a go-routine and 2 buffers?
   864  	readBuf := fh.readBuf
   865  	n, err := readers.ReadFill(fh.rc, (*readBuf)[:])
   866  	if n == 0 {
   867  		return err
   868  	}
   869  	// possibly err != nil here, but we will process the data and
   870  	// the next call to ReadFull will return 0, err
   871  
   872  	// Check header + 1 byte exists
   873  	if n <= blockHeaderSize {
   874  		if err != nil && err != io.EOF {
   875  			return err // return pending error as it is likely more accurate
   876  		}
   877  		return ErrorEncryptedFileBadHeader
   878  	}
   879  	// Decrypt the block using the nonce
   880  	_, ok := secretbox.Open((*fh.buf)[:0], (*readBuf)[:n], fh.nonce.pointer(), &fh.c.dataKey)
   881  	if !ok {
   882  		if err != nil && err != io.EOF {
   883  			return err // return pending error as it is likely more accurate
   884  		}
   885  		if !fh.c.passBadBlocks {
   886  			return ErrorEncryptedBadBlock
   887  		}
   888  		fs.Errorf(nil, "crypt: ignoring: %v", ErrorEncryptedBadBlock)
   889  		// Zero out the bad block and continue
   890  		for i := range (*fh.buf)[:n] {
   891  			(*fh.buf)[i] = 0
   892  		}
   893  	}
   894  	fh.bufIndex = 0
   895  	fh.bufSize = n - blockHeaderSize
   896  	fh.nonce.increment()
   897  	return nil
   898  }
   899  
   900  // Read as per io.Reader
   901  func (fh *decrypter) Read(p []byte) (n int, err error) {
   902  	fh.mu.Lock()
   903  	defer fh.mu.Unlock()
   904  
   905  	if fh.err != nil {
   906  		return 0, fh.err
   907  	}
   908  	if fh.bufIndex >= fh.bufSize {
   909  		err = fh.fillBuffer()
   910  		if err != nil {
   911  			return 0, fh.finish(err)
   912  		}
   913  	}
   914  	toCopy := fh.bufSize - fh.bufIndex
   915  	if fh.limit >= 0 && fh.limit < int64(toCopy) {
   916  		toCopy = int(fh.limit)
   917  	}
   918  	n = copy(p, (*fh.buf)[fh.bufIndex:fh.bufIndex+toCopy])
   919  	fh.bufIndex += n
   920  	if fh.limit >= 0 {
   921  		fh.limit -= int64(n)
   922  		if fh.limit == 0 {
   923  			return n, fh.finish(io.EOF)
   924  		}
   925  	}
   926  	return n, nil
   927  }
   928  
   929  // calculateUnderlying converts an (offset, limit) in an encrypted file
   930  // into an (underlyingOffset, underlyingLimit) for the underlying file.
   931  //
   932  // It also returns number of bytes to discard after reading the first
   933  // block and number of blocks this is from the start so the nonce can
   934  // be incremented.
   935  func calculateUnderlying(offset, limit int64) (underlyingOffset, underlyingLimit, discard, blocks int64) {
   936  	// blocks we need to seek, plus bytes we need to discard
   937  	blocks, discard = offset/blockDataSize, offset%blockDataSize
   938  
   939  	// Offset in underlying stream we need to seek
   940  	underlyingOffset = int64(fileHeaderSize) + blocks*(blockHeaderSize+blockDataSize)
   941  
   942  	// work out how many blocks we need to read
   943  	underlyingLimit = int64(-1)
   944  	if limit >= 0 {
   945  		// bytes to read beyond the first block
   946  		bytesToRead := limit - (blockDataSize - discard)
   947  
   948  		// Read the first block
   949  		blocksToRead := int64(1)
   950  
   951  		if bytesToRead > 0 {
   952  			// Blocks that need to be read plus left over blocks
   953  			extraBlocksToRead, endBytes := bytesToRead/blockDataSize, bytesToRead%blockDataSize
   954  			if endBytes != 0 {
   955  				// If left over bytes must read another block
   956  				extraBlocksToRead++
   957  			}
   958  			blocksToRead += extraBlocksToRead
   959  		}
   960  
   961  		// Must read a whole number of blocks
   962  		underlyingLimit = blocksToRead * (blockHeaderSize + blockDataSize)
   963  	}
   964  	return
   965  }
   966  
   967  // RangeSeek behaves like a call to Seek(offset int64, whence
   968  // int) with the output wrapped in an io.LimitedReader
   969  // limiting the total length to limit.
   970  //
   971  // RangeSeek with a limit of < 0 is equivalent to a regular Seek.
   972  func (fh *decrypter) RangeSeek(ctx context.Context, offset int64, whence int, limit int64) (int64, error) {
   973  	fh.mu.Lock()
   974  	defer fh.mu.Unlock()
   975  
   976  	if fh.open == nil {
   977  		return 0, fh.finish(errors.New("can't seek - not initialised with newDecrypterSeek"))
   978  	}
   979  	if whence != io.SeekStart {
   980  		return 0, fh.finish(errors.New("can only seek from the start"))
   981  	}
   982  
   983  	// Reset error or return it if not EOF
   984  	if fh.err == io.EOF {
   985  		fh.unFinish()
   986  	} else if fh.err != nil {
   987  		return 0, fh.err
   988  	}
   989  
   990  	underlyingOffset, underlyingLimit, discard, blocks := calculateUnderlying(offset, limit)
   991  
   992  	// Move the nonce on the correct number of blocks from the start
   993  	fh.nonce = fh.initialNonce
   994  	fh.nonce.add(uint64(blocks))
   995  
   996  	// Can we seek underlying stream directly?
   997  	if do, ok := fh.rc.(fs.RangeSeeker); ok {
   998  		// Seek underlying stream directly
   999  		_, err := do.RangeSeek(ctx, underlyingOffset, 0, underlyingLimit)
  1000  		if err != nil {
  1001  			return 0, fh.finish(err)
  1002  		}
  1003  	} else {
  1004  		// if not reopen with seek
  1005  		_ = fh.rc.Close() // close underlying file
  1006  		fh.rc = nil
  1007  
  1008  		// Re-open the underlying object with the offset given
  1009  		rc, err := fh.open(ctx, underlyingOffset, underlyingLimit)
  1010  		if err != nil {
  1011  			return 0, fh.finish(fmt.Errorf("couldn't reopen file with offset and limit: %w", err))
  1012  		}
  1013  
  1014  		// Set the file handle
  1015  		fh.rc = rc
  1016  	}
  1017  
  1018  	// Fill the buffer
  1019  	err := fh.fillBuffer()
  1020  	if err != nil {
  1021  		return 0, fh.finish(err)
  1022  	}
  1023  
  1024  	// Discard bytes from the buffer
  1025  	if int(discard) > fh.bufSize {
  1026  		return 0, fh.finish(ErrorBadSeek)
  1027  	}
  1028  	fh.bufIndex = int(discard)
  1029  
  1030  	// Set the limit
  1031  	fh.limit = limit
  1032  
  1033  	return offset, nil
  1034  }
  1035  
  1036  // Seek implements the io.Seeker interface
  1037  func (fh *decrypter) Seek(offset int64, whence int) (int64, error) {
  1038  	return fh.RangeSeek(context.TODO(), offset, whence, -1)
  1039  }
  1040  
  1041  // finish sets the final error and tidies up
  1042  func (fh *decrypter) finish(err error) error {
  1043  	if fh.err != nil {
  1044  		return fh.err
  1045  	}
  1046  	fh.err = err
  1047  	fh.c.putBlock(fh.buf)
  1048  	fh.buf = nil
  1049  	fh.c.putBlock(fh.readBuf)
  1050  	fh.readBuf = nil
  1051  	return err
  1052  }
  1053  
  1054  // unFinish undoes the effects of finish
  1055  func (fh *decrypter) unFinish() {
  1056  	// Clear error
  1057  	fh.err = nil
  1058  
  1059  	// reinstate the buffers
  1060  	fh.buf = fh.c.getBlock()
  1061  	fh.readBuf = fh.c.getBlock()
  1062  
  1063  	// Empty the buffer
  1064  	fh.bufIndex = 0
  1065  	fh.bufSize = 0
  1066  }
  1067  
  1068  // Close
  1069  func (fh *decrypter) Close() error {
  1070  	fh.mu.Lock()
  1071  	defer fh.mu.Unlock()
  1072  
  1073  	// Check already closed
  1074  	if fh.err == ErrorFileClosed {
  1075  		return fh.err
  1076  	}
  1077  	// Closed before reading EOF so not finish()ed yet
  1078  	if fh.err == nil {
  1079  		_ = fh.finish(io.EOF)
  1080  	}
  1081  	// Show file now closed
  1082  	fh.err = ErrorFileClosed
  1083  	if fh.rc == nil {
  1084  		return nil
  1085  	}
  1086  	return fh.rc.Close()
  1087  }
  1088  
  1089  // finishAndClose does finish then Close()
  1090  //
  1091  // Used when we are returning a nil fh from new
  1092  func (fh *decrypter) finishAndClose(err error) error {
  1093  	_ = fh.finish(err)
  1094  	_ = fh.Close()
  1095  	return err
  1096  }
  1097  
  1098  // DecryptData decrypts the data stream
  1099  func (c *Cipher) DecryptData(rc io.ReadCloser) (io.ReadCloser, error) {
  1100  	out, err := c.newDecrypter(rc)
  1101  	if err != nil {
  1102  		return nil, err
  1103  	}
  1104  	return out, nil
  1105  }
  1106  
  1107  // DecryptDataSeek decrypts the data stream from offset
  1108  //
  1109  // The open function must return a ReadCloser opened to the offset supplied.
  1110  //
  1111  // You must use this form of DecryptData if you might want to Seek the file handle
  1112  func (c *Cipher) DecryptDataSeek(ctx context.Context, open OpenRangeSeek, offset, limit int64) (ReadSeekCloser, error) {
  1113  	out, err := c.newDecrypterSeek(ctx, open, offset, limit)
  1114  	if err != nil {
  1115  		return nil, err
  1116  	}
  1117  	return out, nil
  1118  }
  1119  
  1120  // EncryptedSize calculates the size of the data when encrypted
  1121  func (c *Cipher) EncryptedSize(size int64) int64 {
  1122  	blocks, residue := size/blockDataSize, size%blockDataSize
  1123  	encryptedSize := int64(fileHeaderSize) + blocks*(blockHeaderSize+blockDataSize)
  1124  	if residue != 0 {
  1125  		encryptedSize += blockHeaderSize + residue
  1126  	}
  1127  	return encryptedSize
  1128  }
  1129  
  1130  // DecryptedSize calculates the size of the data when decrypted
  1131  func (c *Cipher) DecryptedSize(size int64) (int64, error) {
  1132  	size -= int64(fileHeaderSize)
  1133  	if size < 0 {
  1134  		return 0, ErrorEncryptedFileTooShort
  1135  	}
  1136  	blocks, residue := size/blockSize, size%blockSize
  1137  	decryptedSize := blocks * blockDataSize
  1138  	if residue != 0 {
  1139  		residue -= blockHeaderSize
  1140  		if residue <= 0 {
  1141  			return 0, ErrorEncryptedFileBadHeader
  1142  		}
  1143  	}
  1144  	decryptedSize += residue
  1145  	return decryptedSize, nil
  1146  }
  1147  
  1148  // check interfaces
  1149  var (
  1150  	_ io.ReadCloser  = (*decrypter)(nil)
  1151  	_ io.Seeker      = (*decrypter)(nil)
  1152  	_ fs.RangeSeeker = (*decrypter)(nil)
  1153  	_ io.Reader      = (*encrypter)(nil)
  1154  )