Skip to content

ContentFilterEncryptedMedia

danielweck edited this page Nov 20, 2014 · 13 revisions

Step-by-step instructions

For a quick turnaround when experimenting with encrypted media resources, you may modify the existing ContentFilter class called "PassThroughFilter" (which by default simply passes the raw data extracted from the zip archive, no byte transformation involved).

When you're done experimenting, you need to make your implementation more permanent: create a new file/class specifically for your ContentFilter, and copy/paste the modified PassThroughFilter. Remember to restore the original PassThroughFilter code!

1) First, register the filter in the PopulateFilterManager() initialisation function, so that the filter gets included in the processing chain:

https://github.com/readium/readium-sdk/blob/develop/ePub3/ePub/initialization.cpp#L40

PassThroughFilter::Register();

2) Secondly, make sure that the SniffPassThroughContent method correctly tests your resource. For example, your may need to decode only certain types of audio and video files:

https://github.com/readium/readium-sdk/blob/feature/ByteRangeStreams/ePub3/ePub/PassThroughFilter.cpp#L37

// "item" is a ManifestItem pointer
auto mediaType = item->MediaType();
return (mediaType == "audio/mp4" || mediaType == "audio/mpeg" || mediaType == "video/mp4" || mediaType == "video/mpeg");

3) Thirdly, you now need to implement the FilterData() decryption routine, which should consume raw bytes (provided by the PassThroughContext instance) and transform them into their decoded form:

https://github.com/readium/readium-sdk/blob/feature/ByteRangeStreams/ePub3/ePub/PassThroughFilter.cpp#L113

Note that by default, the PassThroughFilter returns "OperatingMode::SupportsByteRanges" in the GetOperatingMode() method, which means that your implementation must support arbitrary HTTP byte range requests (i.e. query of bytes within the stream, from a given offset, for a given length).

https://github.com/readium/readium-sdk/blob/feature/ByteRangeStreams/ePub3/ePub/PassThroughFilter.h#L47

Should your de-encryption algorithm not support byte ranges, you may then need to disable support for "OperatingMode::SupportsByteRanges", and instead use the "OperatingMode::RequiresCompleteData" variant (which implies that each encrypted media resource will be entirely loaded in memory).

3) Fourthly, you need to write additional code to calculate the size of the decrypted media resource (by default, the BytesAvailable() method returns the length of the raw byte stream):

https://github.com/readium/readium-sdk/blob/feature/ByteRangeStreams/ePub3/ePub/PassThroughFilter.cpp#L71

This is used in the HTTP protocol to test for the EOF status (End Of File) when a resource is being incrementally requested.

Example

Encryption

This Gist contains the contentFilterChainEncode.java code that implements a naive encryption routine (for demonstration purposes only):

https://gist.github.com/danielweck/d04c5eb9fcb2693e0805

This Gist contains the contentFilterChainEncode.sh shell script that compiles and runs the above Java file:

https://gist.github.com/danielweck/b84c7da78670bb61bb21

Decryption

This Gist contains both the BytesAvailable() and the FilterData() methods, matching the above encryption algorithm:

https://gist.github.com/danielweck/eab6bd6ac63aaeb211b6

Clone this wiki locally