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

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