DRM decrypting tool for Samsung TVs PVR
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

drmdecrypt.c 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  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 <sys/types.h>
  10. #include <sys/stat.h>
  11. #include <stdlib.h>
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <fcntl.h>
  15. #include <libgen.h>
  16. #include <limits.h>
  17. #include <unistd.h>
  18. #include <cpuid.h>
  19. #include "aes.h"
  20. #include "trace.h"
  21. #include "buffer.h"
  22. /* MinGW compatibility */
  23. #if defined(_WIN32) || defined(_WIN64)
  24. #define S_IRGRP (S_IRUSR >> 3)
  25. #define S_IROTH (S_IRGRP >> 3)
  26. #else
  27. #define O_BINARY 0
  28. #endif
  29. /* Helper macros */
  30. #define STR_HELPER(x) #x
  31. #define STR(x) STR_HELPER(x)
  32. /* Version Information */
  33. #ifndef REVISION
  34. #define REVISION ""
  35. #endif
  36. #define VERSION "1.1"
  37. block_state state;
  38. int enable_aesni = 0;
  39. /*
  40. * Check for AES-NI CPU support
  41. */
  42. int Check_CPU_support_AES()
  43. {
  44. #if defined(__INTEL_COMPILER)
  45. int CPUInfo[4] = {-1};
  46. __cpuid(CPUInfo, 1);
  47. return (CPUInfo[2] & 0x2000000);
  48. #else
  49. unsigned int a=1,b,c,d;
  50. __cpuid(1, a,b,c,d);
  51. return (c & 0x2000000);
  52. #endif
  53. }
  54. char *filename(char *path, char *newsuffix)
  55. {
  56. char *end = path + strlen(path);
  57. while(*end != '.' && *end != '/')
  58. --end;
  59. if(newsuffix != NULL)
  60. strcpy(++end, newsuffix);
  61. else
  62. *end = '\0';
  63. return path;
  64. }
  65. int readdrmkey(char *keyfile, int ismdb)
  66. {
  67. unsigned char drmkey[0x10];
  68. char tmpbuf[64];
  69. unsigned int j;
  70. unsigned int pos;
  71. FILE *keyfp;
  72. memset(tmpbuf, '\0', sizeof(tmpbuf));
  73. memset(&state, 0, sizeof(block_state));
  74. state.rounds = 10;
  75. if((keyfp = fopen(keyfile, "rb")))
  76. {
  77. if (ismdb)
  78. fseek(keyfp, 8, SEEK_SET);
  79. for (j = 0; j < 0x10; j++){
  80. if (ismdb)
  81. pos = (j&0xc)+(3-(j&3));
  82. else
  83. pos = j;
  84. if(fread(&drmkey[pos], sizeof(unsigned char), 1, keyfp) != 1){
  85. trace(TRC_ERROR, "short read while reading DRM key");
  86. return 1;
  87. }
  88. }
  89. fclose(keyfp);
  90. for (j = 0; j < sizeof(drmkey); j++)
  91. sprintf(tmpbuf+strlen(tmpbuf), "%02X ", drmkey[j]);
  92. trace(TRC_INFO, "drm key successfully read from %s", basename(keyfile));
  93. trace(TRC_INFO, "KEY: %s", tmpbuf);
  94. if(enable_aesni)
  95. block_init_aesni(&state, drmkey, BLOCK_SIZE);
  96. else
  97. block_init_aes(&state, drmkey, BLOCK_SIZE);
  98. return 0;
  99. }
  100. else
  101. trace(TRC_ERROR, "key file %s not found", basename(keyfile));
  102. return 1;
  103. }
  104. int genoutfilename(char *outfile, char *inffile)
  105. {
  106. FILE *inffp;
  107. unsigned char inf[0x200];
  108. char tmpname[PATH_MAX];
  109. int i;
  110. if((inffp = fopen(inffile, "rb")))
  111. {
  112. fseek(inffp, 0, SEEK_SET);
  113. if(fread(inf, sizeof(unsigned char), 0x200, inffp) != 0x200){
  114. trace(TRC_ERROR, "short read while reading inf file");
  115. return 1;
  116. }
  117. fclose(inffp);
  118. /* build base path */
  119. strcpy(tmpname, basename(inffile));
  120. filename(tmpname, NULL);
  121. strcat(tmpname, "-");
  122. /* http://code.google.com/p/samy-pvr-manager/wiki/InfFileStructure */
  123. /* copy channel name and program title */
  124. for(i=1; i < 0x200; i += 2)
  125. {
  126. if (inf[i])
  127. {
  128. if((inf[i] >= 'A' && inf[i] <= 'z') || (inf[i] >= '0' && inf[i] <= '9'))
  129. strncat(tmpname, (char*)&inf[i], 1);
  130. else
  131. strcat(tmpname, "_");
  132. }
  133. if (i == 0xFF) {
  134. strcat(tmpname, "_-_");
  135. }
  136. }
  137. strcat(tmpname, ".ts");
  138. strcat(outfile, tmpname);
  139. }
  140. else
  141. return 1;
  142. return 0;
  143. }
  144. int decrypt_aes128cbc(unsigned char *pin, int len, unsigned char *pout)
  145. {
  146. int i;
  147. if(len % BLOCK_SIZE != 0)
  148. {
  149. trace(TRC_ERROR, "Decrypt length needs to be a multiple of BLOCK_SIZE");
  150. return 1;
  151. }
  152. for(i=0; i < len; i+=BLOCK_SIZE)
  153. {
  154. if(enable_aesni)
  155. block_decrypt_aesni(&state, pin + i, pout + i);
  156. else
  157. block_decrypt_aes(&state, pin + i, pout + i);
  158. }
  159. return 0;
  160. }
  161. /*
  162. * Decode a MPEG packet
  163. *
  164. * Transport Stream Header:
  165. * ========================
  166. *
  167. * Name | bits | byte msk | Description
  168. * ------------------------+------+----------+-----------------------------------------------
  169. * sync byte | 8 | 0xff | Bit pattern from bit 7 to 0 as 0x47
  170. * Transp. Error Indicator | 1 | 0x80 | Set when a demodulator cannot correct errors from FEC data
  171. * Payload Unit start ind. | 1 | 0x40 | Boolean flag with a value of true means the start of PES
  172. * | | | data or PSI otherwise zero only.
  173. * Transport Priority | 1 | 0x20 | Boolean flag with a value of true means the current packet
  174. * | | | has a higher priority than other packets with the same PID.
  175. * PID | 13 | 0x1fff | Packet identifier
  176. * Scrambling control | 2 | 0xc0 | 00 = not scrambled
  177. * | | | 01 = Reserved for future use (DVB-CSA only)
  178. * | | | 10 = Scrambled with even key (DVB-CSA only)
  179. * | | | 11 = Scrambled with odd key (DVB-CSA only)
  180. * Adaptation field exist | 1 | 0x20 | Boolean flag
  181. * Contains payload | 1 | 0x10 | Boolean flag
  182. * Continuity counter | 4 | 0x0f | Sequence number of payload packets (0x00 to 0x0F)
  183. * | | | Incremented only when a playload is present
  184. *
  185. * Adaptation Field:
  186. * ========================
  187. *
  188. * Name | bits | byte msk | Description
  189. * ------------------------+------+----------+-----------------------------------------------
  190. * Adaptation Field Length | 8 | 0xff | Number of bytes immediately following this byte
  191. * Discontinuity indicator | 1 | 0x80 | Set to 1 if current TS packet is in a discontinuity state
  192. * Random Access indicator | 1 | 0x40 | Set to 1 if PES packet starts a video/audio sequence
  193. * Elementary stream prio | 1 | 0x20 | 1 = higher priority
  194. * PCR flag | 1 | 0x10 | Set to 1 if adaptation field contains a PCR field
  195. * OPCR flag | 1 | 0x08 | Set to 1 if adaptation field contains a OPCR field
  196. * Splicing point flag | 1 | 0x04 | Set to 1 if adaptation field contains a splice countdown field
  197. * Transport private data | 1 | 0x02 | Set to 1 if adaptation field contains private data bytes
  198. * Adapt. field extension | 1 | 0x01 | Set to 1 if adaptation field contains extension
  199. * Below fields optional | | | Depends on flags
  200. * PCR | 33+6+9 | | Program clock reference
  201. * OPCR | 33+6+9 | | Original Program clock reference
  202. * Splice countdown | 8 | 0xff | Indicates how many TS packets from this one a splicing point
  203. * | | | occurs (may be negative)
  204. * Stuffing bytes | 0+ | |
  205. *
  206. *
  207. * See: http://en.wikipedia.org/wiki/MPEG_transport_stream
  208. */
  209. int decode_packet(unsigned char *data)
  210. {
  211. unsigned char tmp[PACKETSIZE];
  212. int offset;
  213. if(data[0] != 0x47)
  214. {
  215. trace(TRC_ERROR, "Not a valid MPEG packet!");
  216. return 1;
  217. }
  218. memcpy(tmp, data, PACKETSIZE);
  219. trace(TRC_DEBUG, "-------------------");
  220. trace(TRC_DEBUG, "Trans. Error Indicator: 0x%x", data[2] & 0x80);
  221. trace(TRC_DEBUG, "Payload Unit start Ind: 0x%x", data[2] & 0x40);
  222. trace(TRC_DEBUG, "Transport Priority : 0x%x", data[2] & 0x20);
  223. trace(TRC_DEBUG, "Scrambling control : 0x%x", data[3] & 0xC0);
  224. trace(TRC_DEBUG, "Adaptation field exist: 0x%x", data[3] & 0x20);
  225. trace(TRC_DEBUG, "Contains payload : 0x%x", data[3] & 0x10);
  226. trace(TRC_DEBUG, "Continuity counter : 0x%x", data[3] & 0x0f);
  227. /* only process scrambled content */
  228. if(((data[3] & 0xC0) != 0xC0) && ((data[3] & 0xC0) != 0x80))
  229. return 1;
  230. if(data[3] & 0x20)
  231. trace(TRC_DEBUG, "Adaptation Field length: 0x%x", data[4]+1);
  232. offset=4;
  233. /* skip adaption field */
  234. if(data[3] & 0x20)
  235. offset += (data[4]+1);
  236. /* remove scrambling bits */
  237. tmp[3] &= 0x3f;
  238. /* decrypt only full blocks (they seem to avoid padding) */
  239. decrypt_aes128cbc(data + offset, ((PACKETSIZE - offset)/BLOCK_SIZE)*BLOCK_SIZE, tmp + offset);
  240. memcpy(data, tmp, sizeof(tmp));
  241. return 0;
  242. }
  243. int decryptsrf(char *srffile, char *inkeyfile, char *outdir)
  244. {
  245. char inffile[PATH_MAX];
  246. char outfile[PATH_MAX];
  247. char *keyfile;
  248. struct packetbuffer pb;
  249. int ismdb, retries, sync_find = 0;
  250. unsigned long filesize = 0;
  251. unsigned long i;
  252. memset(&pb, '\0', sizeof(pb));
  253. memset(inffile, '\0', sizeof(inffile));
  254. memset(outfile, '\0', sizeof(outfile));
  255. strcpy(inffile, srffile);
  256. filename(inffile, "inf");
  257. if (inkeyfile[0] == '\0') {
  258. keyfile = malloc(sizeof(char) * PATH_MAX);
  259. memset(keyfile, '\0', sizeof(char) * PATH_MAX);
  260. strcpy(keyfile, srffile);
  261. filename(keyfile, "mdb");
  262. ismdb = 1;
  263. } else {
  264. keyfile = inkeyfile;
  265. ismdb = 0;
  266. }
  267. /* read drm key from .mdb file or keyfile */
  268. if(readdrmkey(keyfile, ismdb) != 0)
  269. return 1;
  270. if (ismdb)
  271. free(keyfile);
  272. /* generate outfile name based on title from .inf file */
  273. strcpy(outfile, outdir);
  274. if(genoutfilename(outfile, inffile) != 0)
  275. {
  276. strcat(outfile, srffile);
  277. filename(outfile, "ts");
  278. }
  279. trace(TRC_INFO, "Writing to %s", outfile);
  280. pbinit(&pb);
  281. pb.fdwrite = open(outfile, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  282. if(pb.fdwrite == -1)
  283. {
  284. trace(TRC_ERROR, "Cannot open %s for writing", outfile);
  285. return 1;
  286. }
  287. pb.fdread = open(srffile, O_RDONLY | O_BINARY);
  288. if(pb.fdread == -1)
  289. {
  290. trace(TRC_ERROR, "Cannot open %s for reading", srffile);
  291. return 1;
  292. }
  293. /* calculate filesize */
  294. filesize = lseek(pb.fdread, 0, SEEK_END);
  295. lseek(pb.fdread, 0, SEEK_SET);
  296. trace(TRC_INFO, "Filesize %ld", filesize);
  297. resync:
  298. /* try to sync */
  299. sync_find = 0;
  300. retries = 10;
  301. while(sync_find == 0 && retries-- > 0)
  302. {
  303. pbread(&pb);
  304. /* search packets starting with 0x47 */
  305. for(i=0; i < (BUFFERSIZE-PACKETSIZE-PACKETSIZE); i++)
  306. {
  307. if (*(pb.workp+i) == 0x47 && *(pb.workp+i+PACKETSIZE) == 0x47 && *(pb.workp+i+PACKETSIZE+PACKETSIZE) == 0x47)
  308. {
  309. sync_find = 1;
  310. pb.workp += i;
  311. trace(TRC_INFO, "synced at offset %ld", pb.workp-pb.startp);
  312. break;
  313. }
  314. }
  315. }
  316. if (sync_find)
  317. {
  318. while(pb.end == 0)
  319. {
  320. pbread(&pb);
  321. while(pb.workp+PACKETSIZE <= pb.endp)
  322. {
  323. if (*(pb.workp) == 0x47)
  324. {
  325. decode_packet((unsigned char *)pb.workp);
  326. pb.workp += PACKETSIZE;
  327. }
  328. else
  329. {
  330. pbwrite(&pb);
  331. goto resync;
  332. }
  333. }
  334. pbwrite(&pb);
  335. }
  336. }
  337. pbwrite(&pb);
  338. close(pb.fdwrite);
  339. close(pb.fdread);
  340. pbfree(&pb);
  341. return 0;
  342. }
  343. void usage(void)
  344. {
  345. fprintf(stderr, "Usage: drmdecrypt [-dqvx][-k keyfile][-o outdir] infile.srf ...\n");
  346. fprintf(stderr, "Options:\n");
  347. fprintf(stderr, " -d Show debugging output\n");
  348. fprintf(stderr, " -k keyfile Use custom key file instead of mdb\n");
  349. fprintf(stderr, " -o outdir Output directory\n");
  350. fprintf(stderr, " -q Be quiet. Only error output.\n");
  351. fprintf(stderr, " -v Version information\n");
  352. fprintf(stderr, " -x Disable AES-NI support\n");
  353. fprintf(stderr, "\n");
  354. }
  355. int main(int argc, char *argv[])
  356. {
  357. char outdir[PATH_MAX];
  358. char keyfile[PATH_MAX];
  359. int ch;
  360. memset(outdir, '\0', sizeof(outdir));
  361. memset(keyfile, '\0', sizeof(keyfile));
  362. enable_aesni = Check_CPU_support_AES();
  363. while ((ch = getopt(argc, argv, "dk:o:qvx")) != -1)
  364. {
  365. switch (ch)
  366. {
  367. case 'd':
  368. if(tracelevel > TRC_DEBUG)
  369. tracelevel--;
  370. break;
  371. case 'k':
  372. strncpy(keyfile, optarg, sizeof(keyfile));
  373. break;
  374. case 'o':
  375. strncpy(outdir, optarg, sizeof(outdir));
  376. break;
  377. case 'q':
  378. if(tracelevel < TRC_ERROR)
  379. tracelevel++;
  380. break;
  381. case 'v':
  382. fprintf(stderr, "drmdecrypt %s (%s)\n\n", VERSION, STR(REVISION));
  383. fprintf(stderr, "Source: https://code.bluelife.at/decke/drmdecrypt\n");
  384. fprintf(stderr, "License: GNU General Public License\n");
  385. exit(EXIT_SUCCESS);
  386. case 'x':
  387. enable_aesni = 0;
  388. break;
  389. default:
  390. usage();
  391. exit(EXIT_FAILURE);
  392. }
  393. }
  394. if(argc == optind)
  395. {
  396. usage();
  397. exit(EXIT_FAILURE);
  398. }
  399. /* set and verify outdir */
  400. if(strlen(outdir) < 1)
  401. {
  402. strcpy(outdir, argv[optind]);
  403. strcpy(outdir, dirname(outdir));
  404. }
  405. if(outdir[strlen(outdir)-1] != '/')
  406. strcat(outdir, "/");
  407. trace(TRC_INFO, "AES-NI CPU support %s", enable_aesni ? "enabled" : "disabled");
  408. do
  409. {
  410. if(decryptsrf(argv[optind], keyfile, outdir) != 0)
  411. break;
  412. }
  413. while(++optind < argc);
  414. return 0;
  415. }