| 392 | } |
| 393 | |
| 394 | func (r *DecryptReaderAt) ReadAt(p []byte, off int64) (n int, err error) { |
| 395 | if off < 0 || off > r.size { |
| 396 | return 0, fmt.Errorf("offset out of range [0:%d]: %d", r.size, off) |
| 397 | } |
| 398 | if len(p) == 0 { |
| 399 | return 0, nil |
| 400 | } |
| 401 | var cacheUpdate *cachedChunk |
| 402 | chunk := make([]byte, encChunkSize) |
| 403 | for len(p) > 0 && off < r.size { |
| 404 | chunkIndex := off / ChunkSize |
| 405 | chunkOff := chunkIndex * encChunkSize |
| 406 | encSize := r.size + r.chunks*chacha20poly1305.Overhead |
| 407 | chunkSize := min(encSize-chunkOff, encChunkSize) |
| 408 | |
| 409 | cached := r.cache.Load() |
| 410 | var plaintext []byte |
| 411 | if cached != nil && cached.off == chunkOff { |
| 412 | plaintext = cached.data |
| 413 | cacheUpdate = nil |
| 414 | } else { |
| 415 | nn, err := r.src.ReadAt(chunk[:chunkSize], chunkOff) |
| 416 | if err == io.EOF { |
| 417 | if int64(nn) != chunkSize { |
| 418 | err = io.ErrUnexpectedEOF |
| 419 | } else { |
| 420 | err = nil |
| 421 | } |
| 422 | } |
| 423 | if err != nil { |
| 424 | return n, fmt.Errorf("failed to read chunk at offset %d: %w", chunkOff, err) |
| 425 | } |
| 426 | nonce := nonceForChunk(chunkIndex) |
| 427 | if chunkIndex == r.chunks-1 { |
| 428 | setLastChunkFlag(nonce) |
| 429 | } |
| 430 | plaintext, err = r.a.Open(chunk[:0], nonce[:], chunk[:chunkSize], nil) |
| 431 | if err != nil { |
| 432 | return n, fmt.Errorf("failed to decrypt and authenticate chunk at offset %d: %w", chunkOff, err) |
| 433 | } |
| 434 | cacheUpdate = &cachedChunk{off: chunkOff, data: plaintext} |
| 435 | } |
| 436 | |
| 437 | plainChunkOff := int(off - chunkIndex*ChunkSize) |
| 438 | copySize := min(len(plaintext)-plainChunkOff, len(p)) |
| 439 | copy(p, plaintext[plainChunkOff:plainChunkOff+copySize]) |
| 440 | p = p[copySize:] |
| 441 | off += int64(copySize) |
| 442 | n += copySize |
| 443 | } |
| 444 | if cacheUpdate != nil { |
| 445 | r.cache.Store(cacheUpdate) |
| 446 | } |
| 447 | if off == r.size { |
| 448 | return n, io.EOF |
| 449 | } |
| 450 | return n, nil |
| 451 | } |