typo fix
[enigma2-plugins.git] / bitrateviewer / src / bitratecalc / bitratecalc.cpp
1 /*
2 #  BitrateCalculator E2
3 #
4 #  $Id$
5 #
6 #  Coded by Dr.Best (c) 2010
7 #  Support: www.dreambox-tools.info
8 #
9 #  This plugin is licensed under the Creative Commons 
10 #  Attribution-NonCommercial-ShareAlike 3.0 Unported 
11 #  License. To view a copy of this license, visit
12 #  http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative
13 #  Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
14 #
15 #  Alternatively, this plugin may be distributed and executed on hardware which
16 #  is licensed by Dream Multimedia GmbH.
17
18 #  This plugin is NOT free software. It is open source, you are allowed to
19 #  modify it (if you keep the license), but it may not be commercially 
20 #  distributed other than under the conditions noted above.
21 */
22
23 #include "bitratecalc.h"
24 #include <fcntl.h>
25 #include <lib/base/etpm.h>
26 #include <openssl/bn.h>
27 #include <openssl/sha.h>
28
29 eBitrateCalc::eBitrateCalc(int pid, int dvbnamespace, int tsid, int onid, int refreshintervall, int buffer_size): m_size(0), m_refresh_intervall(refreshintervall)
30 {
31         m_send_data_timer = eTimer::create(eApp);
32         CONNECT(m_send_data_timer->timeout, eBitrateCalc::sendDataTimerTimeoutCB);
33         eDVBChannelID chid; //(eDVBNamespace(dvbnamespace), eTransportStreamID(tsid), eOriginalNetworkID(onid));  <-- weird, that does not work
34         chid.dvbnamespace = eDVBNamespace(dvbnamespace);
35         chid.transport_stream_id = eTransportStreamID(tsid);
36         chid.original_network_id = eOriginalNetworkID(onid);
37         ePtr<eDVBResourceManager> res_mgr;
38         eDVBResourceManager::getInstance(res_mgr);
39         eUsePtr<iDVBChannel> channel;
40         int success = 0;
41         m_reader = NULL;
42         if (!res_mgr->allocateChannel(chid, channel, false))
43         {
44                 ePtr<iDVBDemux> demux;
45                 if (!channel->getDemux(demux))
46                 {
47                         if (!demux->createPESReader(eApp, m_reader))
48                         {
49                                 if (!m_reader->connectRead(slot(*this, &eBitrateCalc::dataReady), m_pes_connection))
50                                 {
51                                         channel->connectStateChange(slot(*this, &eBitrateCalc::stateChange), m_channel_connection);
52                                         success = 1;
53                                 }
54                                 else
55                                         eDebug("[eBitrateCalc] connect pes reader failed...");
56                         }
57                         else
58                                 eDebug("[eBitrateCalc] create PES reader failed...");
59                 }
60                 else 
61                         eDebug("[eBitrateCalc] getDemux failed...");
62         }
63         else
64         {
65                 eDebug("[eBitrateCalc] allocate channel failed...trying pvr_allocate_demux");
66                 ePtr<eDVBAllocatedDemux> pvr_allocated_demux;
67                 int i = 0;
68                 if (!res_mgr->allocateDemux(NULL,pvr_allocated_demux,i))
69                 {
70                         eDVBDemux &demux = pvr_allocated_demux->get();
71                         if (!demux.createPESReader(eApp, m_reader))
72                         {
73                                 if (!m_reader->connectRead(slot(*this, &eBitrateCalc::dataReady), m_pes_connection))
74                                         success = 1;
75                                 else
76                                         eDebug("[eBitrateCalc] connect pes reader failed...");
77                         }
78                         else
79                                 eDebug("[eBitrateCalc] create PES reader failed...");
80                 }
81                 else
82                         eDebug("[eBitrateCalc] allocate pvr_allocated_demux failed...");
83         }
84         if (m_reader && success)
85         {
86                 clock_gettime(CLOCK_MONOTONIC, &m_start);
87                 m_reader->setBufferSize(buffer_size);
88                 m_reader->start(pid);
89                 m_send_data_timer->start(m_refresh_intervall, true);
90         }
91         else
92                 sendData(-1,0);
93 }
94
95 void eBitrateCalc::dataReady(const __u8*,  int size)
96 {
97         m_size += size;
98 }
99
100 void eBitrateCalc::sendDataTimerTimeoutCB()
101 {
102         struct timespec now;
103         clock_gettime(CLOCK_MONOTONIC, &now);
104         timespec delta = now - m_start;
105         unsigned int delta_ms = delta.tv_nsec / 1000000 + delta.tv_sec * 1000;
106         if (delta_ms)
107         {
108                 int bitrate =  int(m_size / delta_ms)*8;
109                 sendData(bitrate,1);
110         }               
111         m_send_data_timer->start(m_refresh_intervall, true);
112 }
113
114 void eBitrateCalc::stateChange(iDVBChannel *ch)
115 {
116         int state;
117         if (ch->getState(state))
118                 return;
119         if (state == iDVBChannel::state_release)
120         {
121                 m_send_data_timer = NULL;
122                 m_reader = NULL;
123                 m_pes_connection = NULL;
124                 m_channel_connection = NULL;
125                 sendData(-1,0);
126         }
127 }
128
129 static void rsa_pub1024(unsigned char dest[128],
130                         const unsigned char src[128],
131                         const unsigned char mod[128])
132 {
133         BIGNUM bbuf, bexp, bmod;
134         BN_CTX *ctx;
135
136         ctx = BN_CTX_new();
137         BN_init(&bbuf);
138         BN_init(&bexp);
139         BN_init(&bmod);
140
141         BN_bin2bn(src, 128, &bbuf);
142         BN_bin2bn(mod, 128, &bmod);
143         BN_bin2bn((const unsigned char *)"\x01\x00\x01", 3, &bexp);
144
145         BN_mod_exp(&bbuf, &bbuf, &bexp, &bmod, ctx);
146
147         BN_bn2bin(&bbuf, dest);
148
149         BN_clear_free(&bexp);
150         BN_clear_free(&bmod);
151         BN_clear_free(&bbuf);
152         BN_CTX_free(ctx);
153 }
154
155 static bool decrypt_block(unsigned char dest[128],
156                           const unsigned char *src,
157                           unsigned int len,
158                           const unsigned char mod[128])
159 {
160         unsigned char hash[20];
161         SHA_CTX ctx;
162
163         if ((len != 128) &&
164             (len != 202))
165                 return false;
166
167         rsa_pub1024(dest, src, mod);
168
169         SHA1_Init(&ctx);
170         SHA1_Update(&ctx, &dest[1], 106);
171         if (len == 202)
172                 SHA1_Update(&ctx, &src[131], 61);
173         SHA1_Final(hash, &ctx);
174
175         return (memcmp(hash, &dest[107], 20) == 0);
176 }
177
178 static bool read_random(unsigned char *buf, size_t len)
179 {
180         ssize_t ret;
181         int fd;
182
183         fd = open("/dev/urandom", O_RDONLY);
184         if (fd < 0) {
185                 perror("/dev/urandom");
186                 return false;
187         }
188
189         ret = read(fd, buf, len);
190
191         close(fd);
192
193         if (ret != (ssize_t)len) {
194                 fprintf(stderr, "could not read random data\n");
195                 return false;
196         }
197
198         return true;
199 }
200
201 static bool validate_cert(unsigned char dest[128],
202                           const unsigned char *src,
203                           const unsigned char mod[128])
204 {
205         unsigned char buf[128];
206
207         if (!decrypt_block(buf, &src[8], 210 - 8, mod))
208                 return false;
209
210         memcpy(&dest[0], &buf[36], 71);
211         memcpy(&dest[71], &src[131 + 8], 57);
212         return true;
213 }
214
215 static const unsigned char tpm_root_mod[128] = {
216         0x9F,0x7C,0xE4,0x47,0xC9,0xB4,0xF4,0x23,0x26,0xCE,0xB3,0xFE,0xDA,0xC9,0x55,0x60,
217         0xD8,0x8C,0x73,0x6F,0x90,0x9B,0x5C,0x62,0xC0,0x89,0xD1,0x8C,0x9E,0x4A,0x54,0xC5,
218         0x58,0xA1,0xB8,0x13,0x35,0x45,0x02,0xC9,0xB2,0xE6,0x74,0x89,0xDE,0xCD,0x9D,0x11,
219         0xDD,0xC7,0xF4,0xE4,0xE4,0xBC,0xDB,0x9C,0xEA,0x7D,0xAD,0xDA,0x74,0x72,0x9B,0xDC,
220         0xBC,0x18,0x33,0xE7,0xAF,0x7C,0xAE,0x0C,0xE3,0xB5,0x84,0x8D,0x0D,0x8D,0x9D,0x32,
221         0xD0,0xCE,0xD5,0x71,0x09,0x84,0x63,0xA8,0x29,0x99,0xDC,0x3C,0x22,0x78,0xE8,0x87,
222         0x8F,0x02,0x3B,0x53,0x6D,0xD5,0xF0,0xA3,0x5F,0xB7,0x54,0x09,0xDE,0xA7,0xF1,0xC9,
223         0xAE,0x8A,0xD7,0xD2,0xCF,0xB2,0x2E,0x13,0xFB,0xAC,0x6A,0xDF,0xB1,0x1D,0x3A,0x3F,
224 };
225
226 #define CLEN 8
227
228 static bool signature()
229 {
230         int chk = 1;
231         FILE *fp; 
232         fp = fopen ("/proc/stb/info/model", "r");
233         if (fp)
234         {
235                 char line[256];
236                 int n;
237                 fgets(line, sizeof(line), fp);
238                 if ((n = strlen(line)) && line[n - 1] == '\n')
239                          line[n - 1] = '\0';
240                 fclose(fp);
241                 if (strstr(line,"dm7025"))
242                         chk = 0;
243         }
244         if (chk)
245         {
246                 eTPM tpm;
247                 unsigned char rnd[CLEN];
248                 /* read random bytes */
249                 if (!read_random(rnd, CLEN))
250                         return 1;
251                 unsigned char level2_mod[128];
252                 unsigned char level3_mod[128];
253                 unsigned char buf[128];
254                 std::string challenge((char*)rnd, CLEN);
255                 std::string response = tpm.challenge(challenge);
256                 unsigned int len = response.size();
257                 unsigned char val[len];
258                 if ( len != 128 )
259                         return false;
260                 memcpy(val, response.c_str(), len);
261                 std::string cert = tpm.getCert(eTPM::TPMD_DT_LEVEL2_CERT);
262                 if ( cert.size() != 210 || !validate_cert(level2_mod, (const unsigned char*) cert.c_str(), tpm_root_mod))
263                         return false;
264                 cert = tpm.getCert(eTPM::TPMD_DT_LEVEL3_CERT);
265                 if ( cert.size() != 210 || !validate_cert(level3_mod, (const unsigned char*) cert.c_str(), level2_mod))
266                         return false;
267                 if (!decrypt_block(buf, val, 128, level3_mod))
268                         return false;
269                 if (memcmp(&buf[80], rnd, CLEN))
270                         return false;
271                 return true;
272         }
273         else
274                 return true;
275 }
276
277 // eBitrateCalculator replacement
278 extern "C" {
279
280 struct eBitrateCalculatorPy
281 {
282         PyObject_HEAD
283         eBitrateCalc *bc;
284 };
285
286 static int
287 eBitrateCalculatorPy_traverse(eBitrateCalculatorPy *self, visitproc visit, void *arg)
288 {
289         PyObject *obj = self->bc->dataSent.getSteal();
290         if (obj)
291                 Py_VISIT(obj);
292         return 0;
293 }
294
295 static int
296 eBitrateCalculatorPy_clear(eBitrateCalculatorPy *self)
297 {
298         PyObject *obj = self->bc->dataSent.getSteal(true);
299         if (obj)
300                 Py_CLEAR(obj);
301         delete self->bc;
302         return 0;
303 }
304
305 static void
306 eBitrateCalculatorPy_dealloc(eBitrateCalculatorPy* self)
307 {
308         eBitrateCalculatorPy_clear(self);
309         self->ob_type->tp_free((PyObject*)self);
310 }
311
312 static PyObject *
313 eBitrateCalculatorPy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
314 {
315         eBitrateCalculatorPy *self = (eBitrateCalculatorPy *)type->tp_alloc(type, 0);
316         int size = PyTuple_Size(args);
317         int pid, dvbnamespace, tsid, onid, refreshinterval, buffer_size;
318         if (size < 6 || !PyArg_ParseTuple(args, "iiiiii", &pid, &dvbnamespace, &tsid, &onid, &refreshinterval, &buffer_size))
319                 return NULL;
320         self->bc = new eBitrateCalc(pid, dvbnamespace, tsid, onid, refreshinterval, buffer_size);
321         return (PyObject *)self;
322 }
323
324 static PyObject *
325 eBitrateCalculatorPy_get_cb_list(eBitrateCalculatorPy *self, void *closure)
326 {
327         return self->bc->dataSent.get();
328 }
329
330 static PyGetSetDef eBitrateCalculatorPy_getseters[] = {
331         {"callback",
332          (getter)eBitrateCalculatorPy_get_cb_list, (setter)0,
333          "returns the callback python list",
334          NULL},
335         {NULL} /* Sentinel */
336 };
337
338 static PyTypeObject eBitrateCalculatorPyType = {
339         PyObject_HEAD_INIT(NULL)
340         0, /*ob_size*/
341         "eBitrateImpl.eBitrateCalculator", /*tp_name*/
342         sizeof(eBitrateCalculatorPy), /*tp_basicsize*/
343         0, /*tp_itemsize*/
344         (destructor)eBitrateCalculatorPy_dealloc, /*tp_dealloc*/
345         0, /*tp_print*/
346         0, /*tp_getattr*/
347         0, /*tp_setattr*/
348         0, /*tp_compare*/
349         0, /*tp_repr*/
350         0, /*tp_as_number*/
351         0, /*tp_as_sequence*/
352         0, /*tp_as_mapping*/
353         0, /*tp_hash */
354         0, /*tp_call*/
355         0, /*tp_str*/
356         0, /*tp_getattro*/
357         0, /*tp_setattro*/
358         0, /*tp_as_buffer*/
359         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
360         "eBitrateCalculator objects", /* tp_doc */
361         (traverseproc)eBitrateCalculatorPy_traverse, /* tp_traverse */
362         (inquiry)eBitrateCalculatorPy_clear, /* tp_clear */
363         0, /* tp_richcompare */
364         0, /* tp_weaklistoffset */
365         0, /* tp_iter */
366         0, /* tp_iternext */
367         0, /* tp_methods */
368         0, /* tp_members */
369         eBitrateCalculatorPy_getseters, /* tp_getset */
370         0, /* tp_base */
371         0, /* tp_dict */
372         0, /* tp_descr_get */
373         0, /* tp_descr_set */
374         0, /* tp_dictoffset */
375         0, /* tp_init */
376         0, /* tp_alloc */
377         eBitrateCalculatorPy_new, /* tp_new */
378 };
379
380 static PyMethodDef module_methods[] = {
381         {NULL}  /* Sentinel */
382 };
383
384 PyMODINIT_FUNC
385 initbitratecalc(void)
386 {
387         bool init = signature();
388         PyObject* m = Py_InitModule3("bitratecalc", module_methods,
389                 "Module that implements bitrate calculations.");
390         if (m == NULL)
391                 return;
392         if (!init)
393         {
394                 PyErr_SetString(PyExc_TypeError, "TPM challenge failed");
395                 return; 
396         }
397         if (!PyType_Ready(&eBitrateCalculatorPyType))
398         {
399                 Org_Py_INCREF((PyObject*)&eBitrateCalculatorPyType);
400                 PyModule_AddObject(m, "eBitrateCalculator", (PyObject*)&eBitrateCalculatorPyType);
401         }
402 }
403 };