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