Skip to content

Commit 26f477e

Browse files
committed
Fix crash when attempting to LCP decrypt an unencrypted resource
1 parent 35b5072 commit 26f477e

File tree

2 files changed

+23
-2
lines changed

2 files changed

+23
-2
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ All notable changes to this project will be documented in this file. Take a look
1919

2020
* Support for asynchronous callbacks with `onCreatePublication` (contributed by [@smoores-dev](https://github.com/readium/swift-toolkit/pull/673)).
2121

22+
### Fixed
23+
24+
#### LCP
25+
26+
* Fixed crash when an EPUB resource is declared as LCP-encrypted in the manifest but contains unencrypted data.
27+
2228

2329
## [3.5.0]
2430

Sources/LCP/Content Protection/LCPDecryptor.swift

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import ReadiumInternal
99
import ReadiumShared
1010

1111
private let lcpScheme = "http://readium.org/2014/01/lcp"
12-
private let AESBlockSize: UInt64 = 16 // bytes
1312

1413
/// Decrypts a resource protected with LCP.
1514
final class LCPDecryptor {
@@ -117,7 +116,7 @@ final class LCPDecryptor {
117116
guard let length = length else {
118117
return failure(.requiredEstimatedLength)
119118
}
120-
guard length >= 2 * AESBlockSize else {
119+
guard length.isValidAESChunk else {
121120
return failure(.invalidCBCData)
122121
}
123122

@@ -207,6 +206,10 @@ final class LCPDecryptor {
207206
private extension LCPLicense {
208207
func decryptFully(data: ReadResult<Data>, isDeflated: Bool) async -> ReadResult<Data> {
209208
data.flatMap {
209+
guard UInt64($0.count).isValidAESChunk else {
210+
return .failure(.decoding(LCPDecryptor.Error.invalidCBCData))
211+
}
212+
210213
do {
211214
// Decrypts the resource.
212215
guard var data = try self.decipher($0) else {
@@ -242,3 +245,15 @@ private extension ReadiumShared.Encryption {
242245
algorithm == "http://www.w3.org/2001/04/xmlenc#aes256-cbc"
243246
}
244247
}
248+
249+
private let AESBlockSize: UInt64 = 16 // bytes
250+
251+
private extension UInt64 {
252+
/// Checks if this number is a valid CBC length - i.e. a multiple of AES
253+
/// block size.
254+
/// If not, the file is likely not actually encrypted despite being declared
255+
/// as such.
256+
var isValidAESChunk: Bool {
257+
self >= 2 * AESBlockSize && self % AESBlockSize == 0
258+
}
259+
}

0 commit comments

Comments
 (0)