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 )