Skip to main content
Skip table of contents

Supporting Readium LCP DRM

Introduction

This guide details the steps you need to take in order to to load publications protected with the Readium LCP DRM in your app.

The guide assumes that you have included the Readium LCP package, and the private library you obtain by contacting EDRLab.

Android

  1. Retrieve the LcpLicense from the LCP-protected EPUB publication asset following the guides on https://github.com/readium/kotlin-toolkit:

  2. Create an EncryptionMethod capable of decrypting bytes from the publication. Remember to inflate the data if compressed.

    KOTLIN
    import com.colibrio.core.drm.XmlEncryptionEntry
    import com.colibrio.core.io.base.ResourceMetadata
    import com.colibrio.readingsystem.base.EncryptionMethod
    import kotlinx.coroutines.runBlocking
    import org.readium.r2.lcp.LcpLicense
    import java.io.ByteArrayOutputStream
    import java.util.zip.Inflater
    
    class LcpEncryptionMethod(private val lcpLicense: LcpLicense) : EncryptionMethod {
        override val name: String = "http://www.w3.org/2001/04/xmlenc#aes256-cbc"
    
        override fun decrypt(
            encryptedBytes: ByteArray,
            encryptedResourceMetadata: ResourceMetadata,
            xmlEncryptionEntry: XmlEncryptionEntry
        ): ByteArray {
            val decryptedByteArray = runBlocking { lcpLicense.decrypt(encryptedBytes).getOrNull() }
            requireNotNull(decryptedByteArray)
    
            return if (xmlEncryptionEntry.encryptionProperties?.compressionMethod == DEFLATE_ALGORITHM) {
                inflateData(
                    decryptedByteArray
                )
            } else {
                decryptedByteArray
            }
        }
    
        private fun inflateData(deflatedData: ByteArray): ByteArray {
            val inflater = Inflater(true)
            inflater.setInput(deflatedData)
    
            val outputStream = ByteArrayOutputStream()
            val buffer = ByteArray(1024)
    
            try {
                while (!inflater.finished()) {
                    val count = inflater.inflate(buffer)
                    outputStream.write(buffer, 0, count)
                }
            } finally {
                inflater.end()
            }
    
            return outputStream.toByteArray()
        }
    
        companion object {
            private const val DEFLATE_ALGORITHM = 8
        }
    }
  3. Pass the encryption method when loading the EPUB file using the ReadingSystemEngine:

    KOTLIN
    readingSystemEngine.loadEpub(
        EpubResourceProviderLoadConfig(
            resourceProvider,
            readingSessionOptions,
            hashSignature = publicationHashSignature,
            encryptionMethods = listOf(lcpEncryptionMethod)
        )
    )

iOS

  1. Retrieve the LcpLicense from the LCP-protected EPUB publication asset following the guides on https://github.com/readium/swift-toolkit:

  2. Create an EncryptionMethod capable of decrypting bytes from the publication. Remember to inflate the data if compressed.

    SWIFT
    import ColibrioReader
    import Foundation
    import ReadiumLCP
    
    enum EncryptionMethodError: Error {
        case decryptionFailed
        case inflationFailed
    }
    
    class LcpEncryptionMethod: EncryptionMethod {
        private static let deflateAlgorithm = 8
        
        var name: String = "http://www.w3.org/2001/04/xmlenc#aes256-cbc"
        
        private let lcpLicense: LCPLicense
        
        init(lcpLicense: LCPLicense) {
            self.lcpLicense = lcpLicense
        }
        
        func decrypt(
            data: Data,
            resourceMetadata: ColibrioReader.ResourceMetadata,
            xmlEncryptionEntry: ColibrioReader.XmlEncryptionEntry,
            completion: @escaping (Result<Data, any Error>) -> Void
        ) {
            guard let decryptedData = try? lcpLicense.decipher(data) else {
                print("decryptionFailed")
                completion(.failure(EncryptionMethodError.decryptionFailed))
                return
            }
            
            if xmlEncryptionEntry.encryptionProperties?.compressionMethod == LcpEncryptionMethod.deflateAlgorithm {
                guard let inflatedData = inflate(data: decryptedData) else {
                    print("inflationFailed")
                    completion(.failure(EncryptionMethodError.inflationFailed))
                    return
                }
                
                completion(.success(inflatedData))
            } else {
                completion(.success(decryptedData))
            }
        }
        
        func inflate(data: Data) -> Data? {
            return data.decompress(withAlgorithm: .zlib)
        }
    }
  3. Pass the encryption method when loading the EPUB file using the ReadingSystemEngine:

    SWIFT
    readingSystemEngine.loadEpub(
        EpubResourceProviderLoadConfig(
            resourceProvider,
            readingSessionOptions,
            hashSignature = publicationHashSignature,
            encryptionMethods = listOf(lcpEncryptionMethod)
        )
    )
    await readingSystemEngine.loadEpub(
        config: EpubResourceProviderLoadConfig(
            resourceProvider: resourceProvider,
            readingSessionOptions: readingSessionOptions,
            hashSignature: publicationHashSignature,
            encryptionMethods: [lcpEncryptionMethod]
        )
    )

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.