/*- * Copyright (c) 2008 FUKAUMI Naoki. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(DES) #include /* XXX: these are intermediate data, may not work on another architecture */ uint32_t ks[2][32] = { { 0xb0d03408, 0xcd06ce01, 0x08cc18b8, 0xc2424349, 0xb448204c, 0x0ac68943, 0x602490d0, 0xcb0fc101, 0x1c0c0094, 0x48854aca, 0x546cf454, 0xc440c041, 0x343014e4, 0x8a898e0b, 0x4020b880, 0xccc18cc4, 0xf0646030, 0x860b864e, 0x50b028e0, 0x03c8c088, 0xa82c448c, 0x044bc0cc, 0x30d450e4, 0x054205c3, 0xf8385c60, 0x0e054844, 0x00f8807c, 0x41034c0d, 0x8c8c9c04, 0x0e430305, 0x6c48c8bc, 0x0984840c, }, { 0x000044c0, 0xc14089c0, 0x8024200c, 0x82090285, 0x10807400, 0x098a8180, 0x882444a0, 0x440c0c80, 0x1450c830, 0x010044c2, 0x4820486c, 0x86020204, 0x00d03028, 0x00838108, 0x80040080, 0x064e4904, 0x2428386c, 0x0080050c, 0x00801808, 0x804d8901, 0xa0088098, 0x0c860982, 0x4010c410, 0x41040341, 0x0c082070, 0x0804c60e, 0x40c02894, 0xc0498001, 0xa4001088, 0x0a8a80c8, 0x14d8a870, 0x00094200, }, }; #define XFORM \ do { \ for (i = 1; i < 24; i++) \ pkt.l[i] ^= xor.l[0]; \ for (i = 0; i < 4; i++) \ wbuf[wpos + i] = pkt.b[4 + i]; \ for (i = 4; i < 132; i += 8) \ DES_ecb_encrypt((DES_cblock *)&pkt.b[4 + i], \ (DES_cblock *)&wbuf[wpos + i], &dks[0], \ DES_DECRYPT); \ for (i = 132; i < 188; i += 8) \ DES_ecb_encrypt((DES_cblock *)&pkt.b[4 + i], \ (DES_cblock *)&wbuf[wpos + i], &dks[1], \ DES_DECRYPT); \ wpos += 188; \ } while (/* CONSTCOND */ 0) #elif defined(SIMD) typedef int v4si __attribute__ ((__vector_size__ (16))); #define XFORM \ do { \ for (i = 0; i < 12; i++) \ pkt.v[i] ^= xor.v[i]; \ memcpy(&wbuf[wpos], &pkt.b[4], 188); \ wpos += 188; \ } while (/* CONSTCOND */ 0) #else #define XFORM \ do { \ for (i = 1; i < 24; i++) \ pkt.l[i] ^= xor.l[i]; \ memcpy(&wbuf[wpos], &pkt.b[4], 188); \ wpos += 188; \ } while (/* CONSTCOND */ 0) #endif #define BUFSIZE (256 * 1024) static void sighandler(int sig) { return; } int main(int argc, char *argv[]) { struct cb { struct cb *next; struct cb *prev; uint8_t *data; ssize_t len; struct aiocb aio; } buf[3], *curbuf; struct sigaction sa; sigset_t ss; union { #if !defined(DES) && defined(SIMD) v4si v[12]; #endif uint64_t l[24]; uint8_t b[192]; } pkt, xor; #ifdef DES DES_key_schedule dks[2]; #else uint64_t *xp; uint8_t *xhp; char *xfn; int null = 0, xfd; #endif uint8_t *wbuf; off_t off; int i, pos, ugen, wpos; #ifdef BEGIN_PAT int pat = 0; #endif setprogname(argv[0]); #ifdef DES if (argc != 2) { fprintf(stderr, "usage: %s device > out.ts\n", #else if (argc < 2 || argc > 3) { fprintf(stderr, "usage: %s device [xorfile] > out.ts\n", #endif getprogname()); exit(EXIT_FAILURE); } if ((ugen = open(argv[1], O_RDONLY)) == -1) err(EXIT_FAILURE, "%s", argv[1]); #ifdef DES xor.b[0] = 0x00; xor.b[1] = 0x00; xor.b[2] = 0xb1; xor.b[3] = 0xf2; xor.b[4] = 0x00; xor.b[5] = 0x04; xor.b[6] = 0xf2; xor.b[7] = 0x04; memcpy(dks[0].ks->deslong, ks[0], sizeof(ks[0])); memcpy(dks[1].ks->deslong, ks[1], sizeof(ks[1])); #else if (argc == 3) xfn = argv[2]; else xfn = "SKNET_HDTV_BDA.sys"; if ((xfd = open(xfn, O_RDONLY)) == -1) err(EXIT_FAILURE, "%s", xfn); if ((xhp = mmap(NULL, 1024, PROT_READ, MAP_FILE | MAP_SHARED, xfd, 0)) == MAP_FAILED) err(EXIT_FAILURE, "mmap()"); if (xhp[0] == 0x47 && xhp[1] == 0x1f && xhp[2] == 0xff) { null = 1; /* XOR'ed null packet */ off = 4; } else if (xhp[0x2c8] == 0x8d && xhp[0x2c9] == 0x5f) off = 0xf628; /* CD 1.0 */ else if (xhp[0x2c0] == 0x31 && xhp[0x2c1] == 0xe6) off = 0x12da8; /* CD 1.1 */ else { fprintf(stderr, "unknown file: %s\n", xfn); exit(EXIT_FAILURE); } munmap(xhp, 1024); if ((xp = mmap(NULL, 184, PROT_READ, MAP_FILE | MAP_SHARED, xfd, off)) == MAP_FAILED) err(EXIT_FAILURE, "mmap()"); xor.l[0] = 0; if (null == 1) for (i = 1; i < 24; i++) xor.l[i] = xp[i - 1] ^ ~0ULL; else for (i = 1; i < 24; i++) xor.l[i] = xp[i - 1]; munmap(xp, 184); close(xfd); #endif buf[0].next = &buf[1]; buf[0].prev = &buf[2]; if ((buf[0].data = malloc(BUFSIZE)) == NULL) err(EXIT_FAILURE, "buf[0]"); buf[1].next = &buf[2]; buf[1].prev = &buf[0]; if ((buf[1].data = malloc(BUFSIZE)) == NULL) err(EXIT_FAILURE, "buf[1]"); buf[2].next = &buf[0]; buf[2].prev = &buf[1]; if ((buf[2].data = malloc(BUFSIZE)) == NULL) err(EXIT_FAILURE, "buf[2]"); curbuf = &buf[0]; #define oldbuf curbuf->prev if ((wbuf = malloc((BUFSIZE / 188 + 1) * 188)) == NULL) err(EXIT_FAILURE, "wbuf"); off = 0; pos = 0; wpos = 0; memset(&sa, 0, sizeof(struct sigaction)); sa.sa_sigaction = NULL; sa.sa_handler = sighandler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sigaction(SIGIO, &sa, NULL); sigemptyset(&ss); sigaddset(&ss, SIGIO); #define AIO_READ(buf) \ do { \ memset(&(buf)->aio, 0, sizeof(struct aiocb)); \ (buf)->aio.aio_offset = off; \ (buf)->aio.aio_buf = (buf)->data; \ (buf)->aio.aio_nbytes = BUFSIZE; \ (buf)->aio.aio_fildes = ugen; \ (buf)->aio.aio_sigevent.sigev_notify = SIGEV_SIGNAL; \ (buf)->aio.aio_sigevent.sigev_signo = SIGIO; \ aio_read(&(buf)->aio); \ } while (/* CONSTCOND */ 0) AIO_READ(curbuf); next: if (wpos > 0) { write(STDOUT_FILENO, wbuf, wpos); wpos = 0; } while (aio_error(&curbuf->aio) == EINPROGRESS) sigwait(&ss, &i); while ((curbuf->len = aio_return(&curbuf->aio)) != 0) { if (__predict_false(curbuf->len == -1)) { AIO_READ(curbuf); goto next; } off += curbuf->len; AIO_READ(curbuf->next); retry: if (pos < 0 && (pos + 188) < curbuf->len) { if (curbuf->data[pos + 188] == 0x47) { memcpy(&pkt.b[4], &oldbuf->data[pos + oldbuf->len], -pos); if ((pos + 188) > 0) memcpy(&pkt.b[4 - pos], curbuf->data, pos + 188); goto xform; } else { for (pos++; pos < 0; pos++) if (oldbuf->data[pos + oldbuf->len] == 0x47) goto retry; } } else if (pos < 0) break; sync: for (; pos < curbuf->len; pos++) if (curbuf->data[pos] == 0x47) break; if (__predict_false(pos == curbuf->len)) { pos = 0; curbuf = curbuf->next; goto next; } #ifdef VERBOSE fprintf(stderr, "G"); #endif synced: if ((pos + 188) < curbuf->len) { if (curbuf->data[pos + 188] == 0x47) { memcpy(&pkt.b[4], &curbuf->data[pos], 188); xform: #ifdef BEGIN_PAT if (pat == 1) XFORM; else if ((pkt.b[5] & 0x5f) == 0x40 && pkt.b[6] == 0x00 && (pkt.b[7] & 0x1f) == 0x10) { pat = 1; XFORM; } #else XFORM; #endif pos += 188; goto synced; } else { pos++; goto sync; } } else { #ifdef VERBOSE fprintf(stderr, "."); #endif pos -= curbuf->len; curbuf = curbuf->next; goto next; } } #ifdef BEGIN_PAT if (pat == 1 && (pos + 188) == curbuf->len) { #else if ((pos + 188) == curbuf->len) { #endif memcpy(&pkt.b[4], &oldbuf->data[pos + oldbuf->len], -pos); if ((pos + 188) > 0) memcpy(&pkt.b[4 - pos], curbuf->data, pos + 188); XFORM; write(STDOUT_FILENO, wbuf, wpos); } close(ugen); return EXIT_SUCCESS; }