Skip to content

Commit 12be7fa

Browse files
authored
Fix reading ranges of obfuscated EPUB resources (#82)
1 parent 0218b34 commit 12be7fa

File tree

3 files changed

+28
-28
lines changed

3 files changed

+28
-28
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ All notable changes to this project will be documented in this file. Take a look
4747
#### Streamer
4848

4949
* Fixed the rendering of PDF covers in some edge cases.
50+
* Fixed reading ranges of obfuscated EPUB resources.
5051

5152
#### Navigator
5253

readium/streamer/src/main/java/org/readium/r2/streamer/parser/epub/EpubDeobfuscator.kt

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,49 @@
11
/*
2-
* Module: r2-streamer-kotlin
3-
* Developers: Aferdita Muriqi, Clément Baumannn, Quentin Gliosca
4-
*
5-
* Copyright (c) 2020. Readium Foundation. All rights reserved.
6-
* Use of this source code is governed by a BSD-style license which is detailed in the
7-
* LICENSE file present in the project repository where this source code is maintained.
2+
* Copyright 2020 Readium Foundation. All rights reserved.
3+
* Use of this source code is governed by the BSD-style license
4+
* available in the top-level LICENSE file of the project.
85
*/
96

107
package org.readium.r2.streamer.parser.epub
118

129
import com.mcxiaoke.koi.HASH
1310
import com.mcxiaoke.koi.ext.toHexBytes
14-
import org.readium.r2.shared.fetcher.ProxyResource
15-
import org.readium.r2.shared.fetcher.Resource
16-
import org.readium.r2.shared.fetcher.ResourceTry
17-
import org.readium.r2.shared.fetcher.mapCatching
11+
import org.readium.r2.shared.fetcher.*
1812
import org.readium.r2.shared.publication.encryption.encryption
1913
import kotlin.experimental.xor
2014

2115
internal class EpubDeobfuscator(private val pubId: String) {
2216

2317
fun transform(resource: Resource): Resource = DeobfuscatingResource(resource)
2418

25-
inner class DeobfuscatingResource(resource: Resource): ProxyResource(resource) {
19+
inner class DeobfuscatingResource(resource: Resource): TransformingResource(resource, cacheBytes = true) {
2620

27-
override suspend fun read(range: LongRange?): ResourceTry<ByteArray> {
28-
val algorithm = resource.link().properties.encryption?.algorithm
21+
override suspend fun transform(data: ResourceTry<ByteArray>): ResourceTry<ByteArray> =
22+
data.map { bytes ->
23+
val algorithm = resource.link().properties.encryption?.algorithm
2924

30-
if (algorithm !in algorithm2length.keys)
31-
return resource.read(range)
25+
val obfuscationLength: Int = algorithm2length[algorithm]
26+
?: return@map bytes
3227

33-
return resource.read(range).mapCatching {
34-
val obfuscationLength: Int = algorithm2length[algorithm]!!
3528
val obfuscationKey: ByteArray = when (algorithm) {
3629
"http://ns.adobe.com/pdf/enc#RC" -> getHashKeyAdobe(pubId)
3730
else -> HASH.sha1(pubId).toHexBytes()
3831
}
3932

40-
deobfuscate(it, range, obfuscationKey, obfuscationLength)
41-
it
33+
deobfuscate(bytes = bytes, obfuscationKey = obfuscationKey, obfuscationLength = obfuscationLength)
34+
bytes
4235
}
43-
}
4436
}
4537

4638
private val algorithm2length: Map<String, Int> = mapOf(
4739
"http://www.idpf.org/2008/embedding" to 1040,
4840
"http://ns.adobe.com/pdf/enc#RC" to 1024
4941
)
5042

51-
private fun deobfuscate(bytes: ByteArray, range: LongRange?, obfuscationKey: ByteArray, obfuscationLength: Int) {
43+
private fun deobfuscate(bytes: ByteArray, obfuscationKey: ByteArray, obfuscationLength: Int) {
5244
@Suppress("NAME_SHADOWING")
53-
val range = range ?: (0L until bytes.size)
54-
if (range.first >= obfuscationLength) {
55-
return
56-
}
57-
58-
val toDeobfuscate = Math.max(range.first, 0L)..Math.min(range.last, obfuscationLength - 1L)
59-
for (i in toDeobfuscate.map { it.toInt() })
45+
val toDeobfuscate = 0 until obfuscationLength
46+
for (i in toDeobfuscate)
6047
bytes[i] = bytes[i].xor(obfuscationKey[i % obfuscationKey.size])
6148
}
6249

readium/streamer/src/test/java/org/readium/r2/streamer/parser/epub/EpubDeobfuscatorTest.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
package org.readium.r2.streamer.parser.epub
1111

12+
import kotlinx.coroutines.runBlocking
1213
import org.assertj.core.api.Assertions.assertThat
1314
import org.junit.Test
1415
import org.junit.runner.RunWith
@@ -73,6 +74,17 @@ class EpubDeobfuscatorTest {
7374
assertThat(deobfuscatedRes).isEqualTo(font)
7475
}
7576

77+
@Test
78+
fun testIdpfDeobfuscationWithRange() {
79+
runBlocking {
80+
val deobfuscatedRes = deobfuscate(
81+
"/deobfuscation/cut-cut.obf.woff",
82+
"http://www.idpf.org/2008/embedding"
83+
).read(20L until 40L).getOrThrow()
84+
assertThat(deobfuscatedRes).isEqualTo(font.copyOfRange(20, 40))
85+
}
86+
}
87+
7688
@Test
7789
fun testAdobeDeobfuscation() {
7890
val deobfuscatedRes = deobfuscate(

0 commit comments

Comments
 (0)