Saturday, March 30, 2013

TiVo App - Overview & Conclusion

So I have spent quite a bit of time, and I have a very good understanding of how the TiVo Stream communicates with the application, but unfortunately I am not any closer to getting the TiVo stream to work on my android or PC devices.

Overview of architecture



However, I can't solve the problem in the iOS App


I cannot extract the decryption algorithm for the playlist items, I cannot debug the applications streaming functionality, and I cannot override any code in the whitebox.

My list of clever ideas has run out...for the iOS App.

Next: Understanding how the TiVo Stream hardware works




Tivo App - Debugger Checks

I have accepted I will never be able to take the TiVo Stream's whiteboxkey and the TivoCrypt and calculate the actual decryption key for a stream, but maybe I can simply reuse the white-box library to use the iPod Touch as a "calculation server" of sorts?

Using GDB to capture Key

Before I try to make a key calculation server, I need to find a way to make the program spit out the key.  I fired up my GDB in a remote terminal and attached to the "Quicksilver" application.  I followed the app along but everytime it started streaming the application would crash with a memory overflow or other random error.

I recalled seeing some code earlier involving "_getpid" and "_sysctl", I thought it was strange that the application would be getting a process ID of another process.  Doing some research I found out that there is a snippet of code that involves both of these commands that is used to determine of the current process is being run in a debugger...


This method involves getting the process ID of the running process and then running sysctl on it and looking for the P_TRACED flag set on processInfo.p_flag.

Looking in the code for this type of code, I stumbled upon a fantastic amount of debugger checks in place:


I spent a few hours trying to modify the code to make the P_TRACED flag never be set, but I quickly realized they had some sort of check in place to see if you had modified code in specific locations (probably inside the whitebox).

At this point, I cannot extract the decryption algorithm, I cannot debug, and I cannot override any code in the whitebox.

TiVo App - TivoProtocolhandler."compareURLData:withdata" method

As we saw earlier, the TivoProtocolHandler."compareURLData:withdata" method takes two arguments, the first being the tivocrypt:// folder converted from hex to bytes, and the second being the whitebox key that was retrieved from the TiVo stream via the "key.scbin" request.

TivoProtocolhandler."compareURLData:withData" analysis


Pulling up this method in IDA Pro...


Wow. That is definitely a white-box obfuscated piece of code.  I tried to decypher it but they start pushing data into random variables and it just becomes impossible to test without a debugger.


At this point, I have to accept the fact that the iOS device never exposes the decryption key, and the algorithm & code to calculate the actual key is so convoluted it would take months to even get close to what would probably be an incorrect answer (there is no way of even knowing if you are close).

I started to think...if I can have my iPod Touch on all the time and publicly expose this method, I could just send in the two arguments (via HTTP) and have it spit out the key...

TiVo App - tivocrypt Schema

We saw that the playlist.m3u8 that is streamed to the iOS device uses what Apple coins as "HTTP Live Streaming".  More specifically, there is a line in the playlist that specifies that the content is encrypted and where its decryption key is stored...

#EXT-X-KEY:METHOD=AES-128,URI="tivocrypt:///29919494ac3b53ab93ba79b17cd06819"

Custom "tivocrypt" Scheme

So I know that the iOS will attempt to hit that URL to retrieve the key, but where is the code that handles that?  And can we extract the key programmatically?

I found a location where the "tivocrypt" string was used on a URL in TiVoProtocolHandler."startLoading"(), this sounds exactly like what we want.


I spent quite a bit of time understanding what this method does, my pseudo code:
  1. Read the incoming request URLs absolute string ("tivocrypt:///{32-hex characters}"), grab the data to the right of "tivoCrypt://" (This should come from the iphone internally)
  2. Split the "/{32-hex characters}" on "/", grab the 2nd string in the array
  3. Loops over the string, converting it to a 16-byte binary called "CompareUrlData"
  4. Call this["compareURLData:withData:"]( CompareUrlData, WithData) to get a new Data object, this new object is our AES-128 key for decrypting video...
  5. Create NsUrlResponse with a NsUrlResponse["initWithURL:MIMEType:expectedContentLength:textEncodingName:"](this["request"]()["URL"]();, "application/octet-stream", Content["length"](), ???); (this should be sent back to the iphone internally)
  6. Have this["client"] (URLProtocolClient) fire off its events
So it is clear, "compareURLData:withData" is taking in some data and outputting our 16-byte key.  Looking at the actual code, the first parameter is the tivocrypt folder name converted from 32-hex characters to a 16-byte value.  But the second argument?

Well...that would be the White Box Key we got from the TiVo Stream earlier!

So, we know both arguments of "compareURLData:withdata", hopefully its just a simple decryption technique...

TiVo App - Streaming .m3u8 playlists

I had been curious how the actual Tivo Stream was .... streaming... the video to the iPhone, in looking at some logs that run during an actual streaming session I found something interesting:

Mar 30 22:55:13 XXXXX-iPod Quicksilver[1286] <Warning>: Preflighter: Transcoder is happy to stream
Mar 30 22:55:13 XXXXX-iPod Quicksilver[1286] <Warning>: TiVoStreamPreflighter: prereqs:2
Mar 30 22:55:13 XXXXX-iPod Quicksilver[1286] <Warning>: backgroundFetchTranscoderInfo done for XXXXXXXXXXXXXX!
Mar 30 22:55:13 XXXXX-iPod tccd[1299] <Notice>: MS:Notice: Installing: (null) [tccd] (793.00)
Mar 30 22:55:14 XXXXX-iPod Quicksilver[1286] <Warning>: Response for passkey session request: 200, error: (null)
Mar 30 22:55:14 XXXXX-iPod Quicksilver[1286] <Warning>: TiVoStreamPreflighter: Pass Key success
Mar 30 22:55:14 XXXXX-iPod Quicksilver[1286] <Warning>: TiVoStreamPreflighter: prereqs:0
Mar 30 22:55:14 XXXXX-iPod Quicksilver[1286] <Warning>: urlForMFSID:forTSN: string is http://10.0.0.109:49152/live-streaming/{TIVO_GUID}/10160.m3u8
Mar 30 22:55:14 XXXXX-iPod Quicksilver[1286] <Warning>: Creating TiVoViewerViewController with url=http://10.0.0.109:49152/live-streaming/{TIVO_GUID}/10160.m3u8
Mar 30 22:55:14 XXXXX-iPod Quicksilver[1286] <Warning>: Displaying status text: Loading Show
Mar 30 22:55:14 XXXXX-iPod Quicksilver[1286] <Warning>: TiVoViewer: setURL:http://10.0.0.109:49152/live-streaming/{TIVO_GUID}/10160.m3u8
Mar 30 22:55:14 XXXXX-iPod Quicksilver[1286] <Warning>: removeTimeObserver: self.player=0x0, pat.player=0x0, pat.token=0x0
Mar 30 22:55:14 XXXXX-iPod Quicksilver[1286] <Warning>: Sending POST request to http://10.0.0.109:49152/sysinfo/control?config=session&action=releaseclient

Retrieving m3u8 file

I grabbed the url from the log and retrieved its content in my browser, it contained the following:

#EXTM3U
#EXT-X-TIVO-CONTEXT:7
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=8431425,CODECS="avc1.77.31,mp4a.40.2",RESOLUTION=1280x720,TIVOQUAL=BEST
10160/7/2240/playlist.m3u8
#EXT-X-ENDLIST

This file looks like it holds different quality streams, each with their own playlist.m3u8 file.

Retrieving playlist.m3u8 file

Following the path in the previous .m3u8 file I grabbed the playlist.m3u8, it contained the following:
#EXTM3U
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="tivocrypt:///29919494ac3b53ab93ba79b17cd06819"
#EXTINF:2,
0
#EXTINF:2,
1
#EXTINF:2,
2
#EXTINF:2,
3
(I truncated the output, it has many parts)

This is VERY interesting!  It appears that the TiVo Stream sends the data in small pieces specified in playlist.m3u8, encrypted with aes-128.

This appears to be called "HTTP Live Streaming" by Apple in iOS, "HLS" for short: https://developer.apple.com/library/ios/#technotes/tn2288/_index.html#//apple_ref/doc/uid/DTS40012238

Given what I have read about the m3u8 format, it appears that iOS will attempt to hit the given url and it will expect a 128-bit AES key in response to decrypt each file...

Dissecting the Whitebox Key returned by the TiVo Stream

We were able to successfully have the TiVo stream return a whiteboxkey, but what data IS the white box key?

White-box key output

It is important to note that the white-box key changes every X minutes, it is NOT a constant.

Here is the contents of the file:


Well, this is certainly not an AES-128 key.  It is some convoluted key that is probably consumed by a white-box cryptography object.

The header "SKBW" is quite interesting, upon googling "SKB" I found a company called "white cryption" (now cryptanium) that offers a "Secure Key Box" white box solution.  They offer a library for iOS, I imagine this is what TiVo used.  

Product Overview

SKB is a C/C++ library that provides an extensive set of high-level classes and methods for working with the most popular cryptographic algorithms. The library’s unique white-box implementation is specifically designed to hide and protect cryptographic keys at all times. In SKB, keys are always encrypted and cryptographic algorithms operate directly with encrypted keys.
  • Cryptographic keys are always encrypted
  • Diversified code and data
  • Robust white-box cryptography implementation
  • Watermarked program code
  • Security is inseparable from the program code
  • Safe storage of cryptographic keys

It is interesting to note that the parent company of "white cryption" is "intertrust", who has been in the news for suing numerous large companies recently (including HTC, Apple).  They also have a patent application for "Obfuscation techniques for enhacing software security": http://www.google.com/patents/US6668325

I have to accept the reality, I do not have the time or resources to decrypt this white-box cryptography engine.  But do I even have to? What is the white box key even used to decrypt?