From 45945a0ad5de7c61ea07ad37f3e491a3f8761ead Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mickae=CC=88l=20Menu?= Date: Fri, 14 Jan 2022 10:08:42 +0100 Subject: [PATCH] Fix reading ranges of obfuscated EPUB resources --- CHANGELOG.md | 1 + .../streamer/parser/epub/EpubDeobfuscator.kt | 43 +++++++------------ .../parser/epub/EpubDeobfuscatorTest.kt | 12 ++++++ 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5958ce012..452910c1c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ All notable changes to this project will be documented in this file. Take a look #### Streamer * Fixed the rendering of PDF covers in some edge cases. +* Fixed reading ranges of obfuscated EPUB resources. #### Navigator diff --git a/readium/streamer/src/main/java/org/readium/r2/streamer/parser/epub/EpubDeobfuscator.kt b/readium/streamer/src/main/java/org/readium/r2/streamer/parser/epub/EpubDeobfuscator.kt index ccbb47f9c6..e3c3c52e04 100644 --- a/readium/streamer/src/main/java/org/readium/r2/streamer/parser/epub/EpubDeobfuscator.kt +++ b/readium/streamer/src/main/java/org/readium/r2/streamer/parser/epub/EpubDeobfuscator.kt @@ -1,20 +1,14 @@ /* - * Module: r2-streamer-kotlin - * Developers: Aferdita Muriqi, Clément Baumannn, Quentin Gliosca - * - * Copyright (c) 2020. Readium Foundation. All rights reserved. - * Use of this source code is governed by a BSD-style license which is detailed in the - * LICENSE file present in the project repository where this source code is maintained. + * Copyright 2020 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. */ package org.readium.r2.streamer.parser.epub import com.mcxiaoke.koi.HASH import com.mcxiaoke.koi.ext.toHexBytes -import org.readium.r2.shared.fetcher.ProxyResource -import org.readium.r2.shared.fetcher.Resource -import org.readium.r2.shared.fetcher.ResourceTry -import org.readium.r2.shared.fetcher.mapCatching +import org.readium.r2.shared.fetcher.* import org.readium.r2.shared.publication.encryption.encryption import kotlin.experimental.xor @@ -22,25 +16,23 @@ internal class EpubDeobfuscator(private val pubId: String) { fun transform(resource: Resource): Resource = DeobfuscatingResource(resource) - inner class DeobfuscatingResource(resource: Resource): ProxyResource(resource) { + inner class DeobfuscatingResource(resource: Resource): TransformingResource(resource, cacheBytes = true) { - override suspend fun read(range: LongRange?): ResourceTry { - val algorithm = resource.link().properties.encryption?.algorithm + override suspend fun transform(data: ResourceTry): ResourceTry = + data.map { bytes -> + val algorithm = resource.link().properties.encryption?.algorithm - if (algorithm !in algorithm2length.keys) - return resource.read(range) + val obfuscationLength: Int = algorithm2length[algorithm] + ?: return@map bytes - return resource.read(range).mapCatching { - val obfuscationLength: Int = algorithm2length[algorithm]!! val obfuscationKey: ByteArray = when (algorithm) { "http://ns.adobe.com/pdf/enc#RC" -> getHashKeyAdobe(pubId) else -> HASH.sha1(pubId).toHexBytes() } - deobfuscate(it, range, obfuscationKey, obfuscationLength) - it + deobfuscate(bytes = bytes, obfuscationKey = obfuscationKey, obfuscationLength = obfuscationLength) + bytes } - } } private val algorithm2length: Map = mapOf( @@ -48,15 +40,10 @@ internal class EpubDeobfuscator(private val pubId: String) { "http://ns.adobe.com/pdf/enc#RC" to 1024 ) - private fun deobfuscate(bytes: ByteArray, range: LongRange?, obfuscationKey: ByteArray, obfuscationLength: Int) { + private fun deobfuscate(bytes: ByteArray, obfuscationKey: ByteArray, obfuscationLength: Int) { @Suppress("NAME_SHADOWING") - val range = range ?: (0L until bytes.size) - if (range.first >= obfuscationLength) { - return - } - - val toDeobfuscate = Math.max(range.first, 0L)..Math.min(range.last, obfuscationLength - 1L) - for (i in toDeobfuscate.map { it.toInt() }) + val toDeobfuscate = 0 until obfuscationLength + for (i in toDeobfuscate) bytes[i] = bytes[i].xor(obfuscationKey[i % obfuscationKey.size]) } diff --git a/readium/streamer/src/test/java/org/readium/r2/streamer/parser/epub/EpubDeobfuscatorTest.kt b/readium/streamer/src/test/java/org/readium/r2/streamer/parser/epub/EpubDeobfuscatorTest.kt index c0ba1fb3f7..8f75c718ed 100644 --- a/readium/streamer/src/test/java/org/readium/r2/streamer/parser/epub/EpubDeobfuscatorTest.kt +++ b/readium/streamer/src/test/java/org/readium/r2/streamer/parser/epub/EpubDeobfuscatorTest.kt @@ -9,6 +9,7 @@ package org.readium.r2.streamer.parser.epub +import kotlinx.coroutines.runBlocking import org.assertj.core.api.Assertions.assertThat import org.junit.Test import org.junit.runner.RunWith @@ -73,6 +74,17 @@ class EpubDeobfuscatorTest { assertThat(deobfuscatedRes).isEqualTo(font) } + @Test + fun testIdpfDeobfuscationWithRange() { + runBlocking { + val deobfuscatedRes = deobfuscate( + "/deobfuscation/cut-cut.obf.woff", + "http://www.idpf.org/2008/embedding" + ).read(20L until 40L).getOrThrow() + assertThat(deobfuscatedRes).isEqualTo(font.copyOfRange(20, 40)) + } + } + @Test fun testAdobeDeobfuscation() { val deobfuscatedRes = deobfuscate(