/[tivodecode]/tivocom/trunk/CTivoDecode.cpp
ViewVC logotype

Contents of /tivocom/trunk/CTivoDecode.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 254 - (show annotations) (download)
Sun Sep 9 23:26:20 2007 UTC (14 years, 4 months ago) by jeremyd2019
File size: 7142 byte(s)
rework interfaces (bumped typelib version to 1.1).  Add support for decoding the MPEG stream.  Added support to read and write from streams (implementing IStream) and make the versions which take filenames use a stream implementation that wraps file access.  Make OpenTivoFile take the MAK as a parameter.  It has a default value of "" (empty string), which means try to get the MAK from the registry, so either omit that param (for those languages which permit that) or specify it as empty string to use the MAK from the registry.  Added progress reporting of MPEG stream decoding via a connection point.  Progress is updated every 100 frames, and percent complete is provided if the tivo file stream supports Seek and Stat functions

1 // CTivoDecode.cpp : Implementation of CTivoDecode
2
3 #include "stdafx.h"
4 #include "CTivoDecode.h"
5 #include "CTivoFile.h"
6 #include "hasher.h"
7 #include "FileStream.h"
8
9 namespace
10 {
11 static const BYTE globalcurrententropy[] = {0x7B, 0x42, 0x30, 0x41, 0x37, 0x39,
12 0x36, 0x31, 0x33, 0x2D, 0x44, 0x32,
13 0x32, 0x32, 0x2D, 0x34, 0x37, 0x44,
14 0x30, 0x2D, 0x38, 0x39, 0x41, 0x43,
15 0x2D, 0x37, 0x31, 0x30, 0x42, 0x31,
16 0x44, 0x41, 0x44, 0x34, 0x43, 0x46,
17 0x36, 0x7D};
18
19 static const ULONG currententropysize = 0x32;
20 static const DATA_BLOB tivo_legacy_entropy = {1, (BYTE*)""};
21 static LPCTSTR TIVO_SHARINGKEYS_REGKEY = _T("SOFTWARE\\TiVo\\SharingKeys");
22 static LPCTSTR TIVO_MEDIAKEY_REGVALUE = _T("TiVoToGo Media");
23 static LPCTSTR TIVO_METAKEY_REGVALUE = _T("TiVoToGo Metadata");
24 static LPCSTR TIVO_MEDIAKEY_PREFIX = "tivo:";
25 static LPCSTR TIVO_METAKEY_PREFIX = "tivo:TiVo DVR:";
26 static LPCWSTR TIVO_PROTECT_DESCR = L"TiVo Sharing Key";
27
28 static HRESULT get_current_entropy (BYTE* current_entropy)
29 {
30 TCHAR windir[MAX_PATH];
31 WIN32_FIND_DATA FindFileInfo;
32 HANDLE findfilehandle;
33 DWORD vol_serial_num;
34 LPTSTR root;
35 BYTE* buffer = current_entropy + 38;
36
37 memcpy(current_entropy, globalcurrententropy, sizeof(globalcurrententropy));
38
39 if (!GetWindowsDirectory(windir, MAX_PATH))
40 return AtlHresultFromLastError();
41
42 memset(&FindFileInfo, 0, sizeof(FindFileInfo));
43
44 if ((findfilehandle = FindFirstFile(windir, &FindFileInfo)) == INVALID_HANDLE_VALUE)
45 return AtlHresultFromLastError();
46
47 FindClose(findfilehandle);
48
49 memcpy(buffer, &FindFileInfo.ftCreationTime.dwLowDateTime, 4);
50 memcpy(buffer+4, &FindFileInfo.ftCreationTime.dwHighDateTime, 4);
51
52 if ((root = _tcschr(windir, 0x5C)))
53 {
54 *(++root) = '\0';
55 }
56
57 if (!GetVolumeInformation(windir, NULL, 0, &vol_serial_num, NULL, NULL, NULL, 0))
58 return AtlHresultFromLastError();
59
60 memcpy(buffer+8, &vol_serial_num, 4);
61
62 *(buffer+12) = '\0';
63
64 return S_OK;
65 }
66
67 template <typename FreeFunc>
68 class DataBlobRAII : public DATA_BLOB
69 {
70 FreeFunc m_free;
71 public:
72 DataBlobRAII(FreeFunc free, DWORD dataLen = 0, BYTE* dataPtr = NULL)
73 : m_free (free)
74 {
75 cbData = dataLen;
76 pbData = dataPtr;
77 }
78 ~DataBlobRAII()
79 {
80 if (pbData)
81 m_free(pbData);
82 }
83 };
84
85 } // end anonymous namespace
86
87 // CTivoDecode
88
89
90 STDMETHODIMP CTivoDecode::get_mak(BSTR* pVal)
91 {
92 try
93 {
94 DataBlobRAII<void (WINAPI*)(LPVOID)> crypted_data (CoTaskMemFree);
95 DataBlobRAII<HLOCAL (WINAPI*)(HLOCAL)> uncrypted_data (LocalFree);
96
97 try
98 {
99 CRegKey reg;
100 _com_util::CheckError(AtlHresultFromWin32(
101 reg.Open(HKEY_CURRENT_USER, TIVO_SHARINGKEYS_REGKEY, KEY_READ)
102 ));
103
104 _com_util::CheckError(AtlHresultFromWin32(
105 reg.QueryBinaryValue(TIVO_MEDIAKEY_REGVALUE, NULL, &crypted_data.cbData)
106 ));
107
108 crypted_data.pbData = (BYTE*)CoTaskMemAlloc(crypted_data.cbData);
109
110 if (crypted_data.pbData == NULL)
111 _com_raise_error(E_OUTOFMEMORY);
112
113 _com_util::CheckError(AtlHresultFromWin32(
114 reg.QueryBinaryValue(TIVO_MEDIAKEY_REGVALUE, crypted_data.pbData, &crypted_data.cbData)
115 ));
116 }
117 catch (const _com_error & ex)
118 {
119 if (ex.Error() == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
120 return Error(OLESTR("MAK not found"), GUID_NULL, ex.Error());
121 else
122 throw;
123 }
124
125 try
126 {
127 if (!CryptUnprotectData(
128 &crypted_data,
129 NULL,
130 const_cast<DATA_BLOB*>(&tivo_legacy_entropy),
131 NULL,
132 NULL,
133 0,
134 &uncrypted_data))
135 {
136 _com_raise_error(AtlHresultFromLastError());
137 }
138 }
139 catch (const _com_error & ex)
140 {
141 if (ex.Error() == HRESULT_FROM_WIN32(ERROR_INVALID_DATA))
142 {
143 BYTE current_entropy [sizeof(globalcurrententropy) + 13];
144 DATA_BLOB currententropy = {currententropysize, current_entropy};
145
146 _com_util::CheckError(get_current_entropy(current_entropy));
147
148 if (!CryptUnprotectData(
149 &crypted_data,
150 NULL,
151 &currententropy,
152 NULL,
153 NULL,
154 0,
155 &uncrypted_data))
156 {
157 _com_raise_error(AtlHresultFromLastError());
158 }
159 }
160 else
161 throw;
162 }
163
164 /* 5 == strlen("tivo:") */
165 CComBSTR makstr ((LPCSTR)(uncrypted_data.pbData + 5));
166 _com_util::CheckError(makstr.CopyTo(pVal));
167 }
168 catch (const _com_error & ex)
169 {
170 return ex.Error();
171 }
172
173 return S_OK;
174 }
175
176 STDMETHODIMP CTivoDecode::put_mak(BSTR newVal)
177 {
178 USES_CONVERSION;
179
180 std::string mak (OLE2A(newVal));
181
182 std::string metakey (TIVO_MEDIAKEY_PREFIX);
183 std::string mediakey (TIVO_MEDIAKEY_PREFIX);
184 std::string md5key;
185 std::string metakey_tohash (TIVO_METAKEY_PREFIX);
186
187 BYTE current_entropy [sizeof(globalcurrententropy) + 13];
188 DATA_BLOB currententropy = {currententropysize, current_entropy};
189 DATA_BLOB media_data_in, meta_data_in;
190 DataBlobRAII<HLOCAL (WINAPI*)(HLOCAL)> media_data_out (LocalFree), meta_data_out(LocalFree);
191
192 mediakey.append(mak);
193 metakey_tohash.append(mak);
194
195 try
196 {
197 CRegKey reg;
198
199 _com_util::CheckError(AtlHresultFromWin32(
200 reg.Create(HKEY_CURRENT_USER, TIVO_SHARINGKEYS_REGKEY)
201 ));
202
203 _com_util::CheckError(get_current_entropy(current_entropy));
204
205 {
206 Hasher hasher(CALG_MD5);
207
208 hasher (metakey_tohash);
209
210 hasher.finish (md5key);
211 }
212
213 metakey.append(md5key);
214
215 /* +1 for the NUL byte */
216 media_data_in.cbData = (DWORD)mediakey.size() + 1;
217 media_data_in.pbData = (BYTE*)mediakey.data();
218
219 /* +1 for the NUL byte */
220 meta_data_in.cbData = (DWORD)metakey.size() + 1;
221 meta_data_in.pbData = (BYTE*)metakey.data();
222
223 if (!CryptProtectData (
224 &media_data_in,
225 TIVO_PROTECT_DESCR,
226 const_cast<DATA_BLOB*> (&tivo_legacy_entropy),
227 NULL,
228 NULL,
229 0,
230 &media_data_out))
231 {
232 _com_raise_error(AtlHresultFromLastError());
233 }
234
235 if (!CryptProtectData (
236 &meta_data_in,
237 TIVO_PROTECT_DESCR,
238 &currententropy,
239 NULL,
240 NULL,
241 0,
242 &meta_data_out))
243 {
244 _com_raise_error(AtlHresultFromLastError());
245 }
246
247 _com_util::CheckError(AtlHresultFromWin32(
248 reg.SetBinaryValue (TIVO_MEDIAKEY_REGVALUE, media_data_out.pbData, media_data_out.cbData)
249 ));
250
251 _com_util::CheckError(AtlHresultFromWin32(
252 reg.SetBinaryValue (TIVO_METAKEY_REGVALUE, meta_data_out.pbData, meta_data_out.cbData)
253 ));
254 }
255 catch (const _com_error & ex)
256 {
257 return ex.Error();
258 }
259
260 return S_OK;
261 }
262
263 STDMETHODIMP CTivoDecode::OpenTivoFile(BSTR bstrFileName, BSTR bstrMAK, ITivoFile** pTivoFile)
264 {
265 try
266 {
267 IStream * pFileStm;
268 CComPtr<IStream> pStm;
269 _com_util::CheckError(FileStream::OpenFile(OLE2CW(bstrFileName), &pFileStm, FALSE));
270 pStm.Attach(pFileStm);
271 _com_util::CheckError(this->OpenTivoStream(pStm, bstrMAK, pTivoFile));
272 }
273 catch (const _com_error & ex)
274 {
275 return ex.Error();
276 }
277
278 return S_OK;
279 }
280
281 STDMETHODIMP CTivoDecode::OpenTivoStream(IStream* pStm, BSTR bstrMAK, ITivoFile** pTivoFile)
282 {
283 USES_CONVERSION;
284 try
285 {
286 CComObject<CTivoFile>* tivoFileClass = new CComObject<CTivoFile> ();
287 CComPtr<ITivoFile> ref (tivoFileClass);
288 CComBSTR mak (bstrMAK);
289 if (mak == OLESTR(""))
290 {
291 mak.Empty();
292 _com_util::CheckError(this->get_mak(&mak));
293 }
294 _com_util::CheckError(tivoFileClass->Init(mak, pStm));
295 _com_util::CheckError(ref.CopyTo(pTivoFile));
296 }
297 catch (const _com_error & ex)
298 {
299 return ex.Error();
300 }
301
302 return S_OK;
303 }

cvs@jdrake.com
ViewVC Help
Powered by ViewVC 1.1.13