DRM decrypting tool for Samsung TVs PVR
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

drmdecrypt.c 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. /* drmdecrypt -- DRM decrypting tool for Samsung TVs
  2. *
  3. * Copyright (C) 2014 - Bernhard Froehlich <decke@bluelife.at>
  4. * All rights reserved.
  5. *
  6. * This software may be modified and distributed under the terms
  7. * of the GPL v2 license. See the LICENSE file for details.
  8. */
  9. #include <stdlib.h>
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <libgen.h>
  13. #include <limits.h>
  14. #include <unistd.h>
  15. #include <cpuid.h>
  16. #include "aes.h"
  17. #include "trace.h"
  18. block_state state;
  19. int enable_aesni = 0;
  20. /*
  21. * Check for AES-NI CPU support
  22. */
  23. int Check_CPU_support_AES()
  24. {
  25. #if defined(__INTEL_COMPILER)
  26. int CPUInfo[4] = {-1};
  27. __cpuid(CPUInfo, 1);
  28. return (CPUInfo[2] & 0x2000000);
  29. #else
  30. unsigned int a=1,b,c,d;
  31. __cpuid(1, a,b,c,d);
  32. return (c & 0x2000000);
  33. #endif
  34. }
  35. char *filename(char *path, char *newsuffix)
  36. {
  37. char *end = path + strlen(path);
  38. while(*end != '.' && *end != '/')
  39. --end;
  40. if(newsuffix != NULL)
  41. strcpy(++end, newsuffix);
  42. else
  43. *end = '\0';
  44. return path;
  45. }
  46. int readdrmkey(char *mdbfile)
  47. {
  48. unsigned char drmkey[0x10];
  49. char tmpbuf[64];
  50. unsigned int j;
  51. FILE *mdbfp;
  52. memset(tmpbuf, '\0', sizeof(tmpbuf));
  53. memset(&state, 0, sizeof(block_state));
  54. state.rounds = 10;
  55. if((mdbfp = fopen(mdbfile, "rb")))
  56. {
  57. fseek(mdbfp, 8, SEEK_SET);
  58. for (j = 0; j < 0x10; j++){
  59. if(fread(&drmkey[(j&0xc)+(3-(j&3))], sizeof(unsigned char), 1, mdbfp) != 1){
  60. trace(TRC_ERROR, "short read while reading DRM key");
  61. return 1;
  62. }
  63. }
  64. fclose(mdbfp);
  65. for (j = 0; j < sizeof(drmkey); j++)
  66. sprintf(tmpbuf+strlen(tmpbuf), "%02X ", drmkey[j]);
  67. trace(TRC_INFO, "drm key successfully read from %s", basename(mdbfile));
  68. trace(TRC_INFO, "KEY: %s", tmpbuf);
  69. if(enable_aesni)
  70. block_init_aesni(&state, drmkey, BLOCK_SIZE);
  71. else
  72. block_init_aes(&state, drmkey, BLOCK_SIZE);
  73. return 0;
  74. }
  75. else
  76. trace(TRC_ERROR, "mdb file %s not found", basename(mdbfile));
  77. return 1;
  78. }
  79. int genoutfilename(char *outfile, char *inffile)
  80. {
  81. FILE *inffp;
  82. unsigned char inf[0x200];
  83. char tmpname[PATH_MAX];
  84. int i;
  85. if((inffp = fopen(inffile, "rb")))
  86. {
  87. fseek(inffp, 0, SEEK_SET);
  88. if(fread(inf, sizeof(unsigned char), 0x200, inffp) != 0x200){
  89. trace(TRC_ERROR, "short read while reading inf file");
  90. return 1;
  91. }
  92. fclose(inffp);
  93. /* build base path */
  94. strcpy(tmpname, basename(inffile));
  95. filename(tmpname, NULL);
  96. strcat(tmpname, "-");
  97. /* http://code.google.com/p/samy-pvr-manager/wiki/InfFileStructure */
  98. /* copy channel name and program title */
  99. for(i=1; i < 0x200; i += 2)
  100. {
  101. if (inf[i])
  102. {
  103. if((inf[i] >= 'A' && inf[i] <= 'z') || (inf[i] >= '0' && inf[i] <= '9'))
  104. strncat(tmpname, (char*)&inf[i], 1);
  105. else
  106. strcat(tmpname, "_");
  107. }
  108. if (i == 0xFF) {
  109. strcat(tmpname, "_-_");
  110. }
  111. }
  112. strcat(tmpname, ".ts");
  113. strcat(outfile, tmpname);
  114. }
  115. else
  116. return 1;
  117. return 0;
  118. }
  119. int decrypt_aes128cbc(unsigned char *pin, int len, unsigned char *pout)
  120. {
  121. int i;
  122. if(len % BLOCK_SIZE != 0)
  123. {
  124. trace(TRC_ERROR, "Decrypt length needs to be a multiple of BLOCK_SIZE");
  125. return 1;
  126. }
  127. for(i=0; i < len; i+=BLOCK_SIZE)
  128. {
  129. if(enable_aesni)
  130. block_decrypt_aesni(&state, pin + i, pout + i);
  131. else
  132. block_decrypt_aes(&state, pin + i, pout + i);
  133. }
  134. return 0;
  135. }
  136. /*
  137. * Decode a MPEG packet
  138. *
  139. * Transport Stream Header:
  140. * ========================
  141. *
  142. * Name | bits | byte msk | Description
  143. * ------------------------+------+----------+-----------------------------------------------
  144. * sync byte | 8 | 0xff | Bit pattern from bit 7 to 0 as 0x47
  145. * Transp. Error Indicator | 1 | 0x80 | Set when a demodulator cannot correct errors from FEC data
  146. * Payload Unit start ind. | 1 | 0x40 | Boolean flag with a value of true means the start of PES
  147. * | | | data or PSI otherwise zero only.
  148. * Transport Priority | 1 | 0x20 | Boolean flag with a value of true means the current packet
  149. * | | | has a higher priority than other packets with the same PID.
  150. * PID | 13 | 0x1fff | Packet identifier
  151. * Scrambling control | 2 | 0xc0 | 00 = not scrambled
  152. * | | | 01 = Reserved for future use (DVB-CSA only)
  153. * | | | 10 = Scrambled with even key (DVB-CSA only)
  154. * | | | 11 = Scrambled with odd key (DVB-CSA only)
  155. * Adaptation field exist | 1 | 0x20 | Boolean flag
  156. * Contains payload | 1 | 0x10 | Boolean flag
  157. * Continuity counter | 4 | 0x0f | Sequence number of payload packets (0x00 to 0x0F)
  158. * | | | Incremented only when a playload is present
  159. *
  160. * Adaptation Field:
  161. * ========================
  162. *
  163. * Name | bits | byte msk | Description
  164. * ------------------------+------+----------+-----------------------------------------------
  165. * Adaptation Field Length | 8 | 0xff | Number of bytes immediately following this byte
  166. * Discontinuity indicator | 1 | 0x80 | Set to 1 if current TS packet is in a discontinuity state
  167. * Random Access indicator | 1 | 0x40 | Set to 1 if PES packet starts a video/audio sequence
  168. * Elementary stream prio | 1 | 0x20 | 1 = higher priority
  169. * PCR flag | 1 | 0x10 | Set to 1 if adaptation field contains a PCR field
  170. * OPCR flag | 1 | 0x08 | Set to 1 if adaptation field contains a OPCR field
  171. * Splicing point flag | 1 | 0x04 | Set to 1 if adaptation field contains a splice countdown field
  172. * Transport private data | 1 | 0x02 | Set to 1 if adaptation field contains private data bytes
  173. * Adapt. field extension | 1 | 0x01 | Set to 1 if adaptation field contains extension
  174. * Below fields optional | | | Depends on flags
  175. * PCR | 33+6+9 | | Program clock reference
  176. * OPCR | 33+6+9 | | Original Program clock reference
  177. * Splice countdown | 8 | 0xff | Indicates how many TS packets from this one a splicing point
  178. * | | | occurs (may be negative)
  179. * Stuffing bytes | 0+ | |
  180. *
  181. *
  182. * See: http://en.wikipedia.org/wiki/MPEG_transport_stream
  183. */
  184. int decode_packet(unsigned char *data, unsigned char *outdata)
  185. {
  186. int offset;
  187. int scrambling, adaptation;
  188. if(data[0] != 0x47)
  189. {
  190. trace(TRC_ERROR, "Not a valid MPEG packet!");
  191. return 0;
  192. }
  193. memcpy(outdata, data, 188);
  194. scrambling = data[3] & 0xC0;
  195. adaptation = data[3] & 0x20;
  196. if(scrambling == 0x80)
  197. {
  198. trace(TRC_DEBUG, "packet scrambled with even key");
  199. }
  200. else if(scrambling == 0xC0)
  201. {
  202. trace(TRC_DEBUG, "packet scrambled with odd key");
  203. }
  204. else if(scrambling == 0x00)
  205. {
  206. trace(TRC_DEBUG, "packet not scrambled");
  207. return 0;
  208. }
  209. else
  210. {
  211. trace(TRC_ERROR, "scrambling info seems to be invalid!");
  212. return 0;
  213. }
  214. offset=4;
  215. /* skip adaption field */
  216. if(adaptation)
  217. offset += (data[4]+1);
  218. /* remove scrambling bits */
  219. outdata[3] &= 0x3f;
  220. /* decrypt only full blocks (they seem to avoid padding) */
  221. decrypt_aes128cbc(data + offset, ((188 - offset)/BLOCK_SIZE)*BLOCK_SIZE, outdata + offset);
  222. return 1;
  223. }
  224. void usage(void)
  225. {
  226. fprintf(stderr, "Usage: drmdecrypt [-x] [-o outdir] infile.srf ...\n");
  227. }
  228. int main(int argc, char *argv[])
  229. {
  230. char mdbfile[PATH_MAX];
  231. char inffile[PATH_MAX];
  232. char srffile[PATH_MAX];
  233. char outfile[PATH_MAX];
  234. char outdir[PATH_MAX] = ".";
  235. FILE *srffp, *outfp;
  236. int ch, retries;
  237. int sync_find = 0;
  238. unsigned long filesize = 0, foffset = 0;
  239. unsigned long i;
  240. unsigned char buf[1024];
  241. unsigned char outdata[1024];
  242. memset(inffile, '\0', sizeof(inffile));
  243. memset(outfile, '\0', sizeof(outfile));
  244. enable_aesni = Check_CPU_support_AES();
  245. while ((ch = getopt(argc, argv, "o:x")) != -1)
  246. {
  247. switch (ch)
  248. {
  249. case 'o':
  250. strcpy(outdir, optarg);
  251. break;
  252. case 'x':
  253. enable_aesni = 0;
  254. break;
  255. default:
  256. usage();
  257. exit(EXIT_FAILURE);
  258. }
  259. }
  260. if(argc == optind)
  261. {
  262. usage();
  263. exit(EXIT_FAILURE);
  264. }
  265. trace(TRC_INFO, "AES-NI CPU support %s", enable_aesni ? "enabled" : "disabled");
  266. strcpy(srffile, argv[optind]);
  267. strcpy(inffile, srffile);
  268. filename(inffile, "inf");
  269. strcpy(mdbfile, srffile);
  270. filename(mdbfile, "mdb");
  271. /* read drm key from .mdb file */
  272. if(readdrmkey(mdbfile) != 0)
  273. return 1;
  274. /* verify outdir */
  275. if(outdir[strlen(outdir)-1] != '/')
  276. strcat(outdir, "/");
  277. strcpy(outfile, outdir);
  278. /* generate outfile name based on title from .inf file */
  279. if(genoutfilename(outfile, inffile) != 0)
  280. {
  281. strcat(outfile, srffile);
  282. filename(outfile, "ts");
  283. }
  284. trace(TRC_INFO, "Writing to %s", outfile);
  285. if((outfp = fopen(outfile, "wb")) == NULL)
  286. {
  287. trace(TRC_ERROR, "Cannot open %s for writing", outfile);
  288. return 1;
  289. }
  290. if((srffp = fopen(srffile, "rb")) == NULL)
  291. {
  292. trace(TRC_ERROR, "Cannot open %s for reading", srffile);
  293. }
  294. /* calculate filesize */
  295. fseek(srffp, 0, 2);
  296. filesize = ftell(srffp);
  297. rewind(srffp);
  298. trace(TRC_INFO, "Filesize %ld", filesize);
  299. resync:
  300. /* try to sync */
  301. sync_find = 0;
  302. retries = 10;
  303. fseek(srffp, foffset, SEEK_SET);
  304. while(sync_find == 0 && retries-- > 0)
  305. {
  306. if(fread(buf, sizeof(unsigned char), sizeof(buf), srffp) != sizeof(buf)){
  307. trace(TRC_INFO, "short read while resyncing");
  308. break;
  309. }
  310. /* search 188byte packets starting with 0x47 */
  311. for(i=0; i < (sizeof(buf)-188-188); i++)
  312. {
  313. if (buf[i] == 0x47 && buf[i+188] == 0x47 && buf[i+188+188] == 0x47)
  314. {
  315. sync_find = 1;
  316. foffset += i;
  317. fseek(srffp, foffset, SEEK_SET);
  318. trace(TRC_INFO, "synced at offset %ld", foffset);
  319. break;
  320. }
  321. }
  322. }
  323. if (sync_find)
  324. {
  325. for(i=0; foffset+i < filesize; i+= 188)
  326. {
  327. if(fread(buf, sizeof(unsigned char), 188, srffp) != 188){
  328. trace(TRC_INFO, "short read while reading stream");
  329. break;
  330. }
  331. if (buf[0] == 0x47)
  332. {
  333. decode_packet(buf, outdata);
  334. fwrite(outdata, sizeof(unsigned char), 188, outfp);
  335. }
  336. else
  337. {
  338. foffset += i;
  339. trace(TRC_WARN, "lost sync at %ld", foffset);
  340. goto resync;
  341. }
  342. }
  343. }
  344. fclose(srffp);
  345. fclose(outfp);
  346. return 0;
  347. }