From 364f88f3f3f501a543f67bed6449cb2e7128b5c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96man?= Date: Sat, 12 Jan 2008 07:37:08 +0000 Subject: [PATCH] Add a code word client and descrambling code. --- Makefile | 11 +- cwc.c | 873 +++++++++++++++++++++++++++++++++++ cwc.h | 26 ++ ffdecsa/FFdecsa.c | 880 +++++++++++++++++++++++++++++++++++ ffdecsa/FFdecsa.h | 62 +++ ffdecsa/fftable.h | 56 +++ ffdecsa/parallel_064_mmx.h | 83 ++++ ffdecsa/parallel_generic.h | 102 +++++ ffdecsa/stream.c | 906 +++++++++++++++++++++++++++++++++++++ krypt.c | 8 + main.c | 7 +- transports.c | 18 +- tsdemux.c | 27 +- tvhead.h | 29 +- 14 files changed, 3051 insertions(+), 37 deletions(-) create mode 100644 cwc.c create mode 100644 cwc.h create mode 100644 ffdecsa/FFdecsa.c create mode 100644 ffdecsa/FFdecsa.h create mode 100644 ffdecsa/fftable.h create mode 100644 ffdecsa/parallel_064_mmx.h create mode 100644 ffdecsa/parallel_generic.h create mode 100644 ffdecsa/stream.c create mode 100644 krypt.c diff --git a/Makefile b/Makefile index 6aa28a62..facc62b6 100644 --- a/Makefile +++ b/Makefile @@ -22,16 +22,21 @@ SRCS += htsclient.c rtsp.c rtp.c SRCS += v4l.c +SRCS += cwc.c krypt.c + +VPATH += ffdecsa +SRCS += FFdecsa.c + PROG = tvheadend -CFLAGS += -g -Wall -Werror -O2 +CFLAGS += -g -Wall -Werror -O2 -mmmx CFLAGS += -I$(INCLUDES_INSTALL_BASE) $(HTS_CFLAGS) CFLAGS += -Wno-deprecated-declarations CFLAGS += -D_LARGEFILE64_SOURCE CFLAGS += -DENABLE_INPUT_IPTV -DENABLE_INPUT_DVB -DENABLE_INPUT_V4L -LDFLAGS += -L$(LIBS_INSTALL_BASE) -rdynamic +LDFLAGS += -L$(LIBS_INSTALL_BASE) SLIBS += ${LIBHTS_SLIBS} -DLIBS += ${LIBHTS_DLIBS} +DLIBS += ${LIBHTS_DLIBS} -lcrypt # # ffmpeg diff --git a/cwc.c b/cwc.c new file mode 100644 index 00000000..c64f5f21 --- /dev/null +++ b/cwc.c @@ -0,0 +1,873 @@ +/* + * tvheadend, CWC interface + * Copyright (C) 2007 Andreas Öman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tvhead.h" +#include "tcp.h" +#include "psi.h" +#include "tsdemux.h" +#include "ffdecsa/FFdecsa.h" +#include "dispatch.h" + +#define CWC_KEEPALIVE_INTERVAL 600 + +#define CWS_NETMSGSIZE 240 +#define CWS_FIRSTCMDNO 0xe0 + +typedef enum { + MSG_CLIENT_2_SERVER_LOGIN = CWS_FIRSTCMDNO, + MSG_CLIENT_2_SERVER_LOGIN_ACK, + MSG_CLIENT_2_SERVER_LOGIN_NAK, + MSG_CARD_DATA_REQ, + MSG_CARD_DATA, + MSG_SERVER_2_CLIENT_NAME, + MSG_SERVER_2_CLIENT_NAME_ACK, + MSG_SERVER_2_CLIENT_NAME_NAK, + MSG_SERVER_2_CLIENT_LOGIN, + MSG_SERVER_2_CLIENT_LOGIN_ACK, + MSG_SERVER_2_CLIENT_LOGIN_NAK, + MSG_ADMIN, + MSG_ADMIN_ACK, + MSG_ADMIN_LOGIN, + MSG_ADMIN_LOGIN_ACK, + MSG_ADMIN_LOGIN_NAK, + MSG_ADMIN_COMMAND, + MSG_ADMIN_COMMAND_ACK, + MSG_ADMIN_COMMAND_NAK, + MSG_KEEPALIVE = CWS_FIRSTCMDNO + 0x1d +} net_msg_type_t; + +extern char *cwc_krypt(const char *key, const char *salt); + +static LIST_HEAD(, cwc_transport) cwc_pending_requests; + +typedef struct cwc_transport { + th_descrambler_t ct_head; + + th_transport_t *ct_transport; + + struct cwc *ct_cwc; + + LIST_ENTRY(cwc_transport) ct_cwc_link; /* Always linked */ + + LIST_ENTRY(cwc_transport) ct_link; /* linked if we are waiting + on a reply from server */ + int ct_pending; + + enum { + CT_UNKNOWN, + CT_RESOLVED, + CT_FORBIDDEN + } ct_keystate; + + uint16_t ct_seq; + + uint8_t ct_ecm[256]; + int ct_ecmsize; + + void *ct_keys; + +#define CT_CLUSTER_SIZE 32 + + uint8_t ct_tsbcluster[188 * CT_CLUSTER_SIZE]; + int ct_fill; + +} cwc_transport_t; + + + + + +typedef struct cwc { + tcp_session_t cwc_tcp_session; /* Must be first */ + + LIST_ENTRY(cwc) cwc_link; + + LIST_HEAD(, cwc_transport) cwc_transports; + + enum { + CWC_STATE_IDLE, + CWC_STATE_WAIT_LOGIN_KEY, + CWC_STATE_WAIT_LOGIN_ACK, + CWC_STATE_WAIT_CARD_DATA, + CWC_STATE_RUNNING, + } cwc_state; + + uint16_t cwc_caid; + + uint16_t cwc_seq; + + uint8_t cwc_key[16]; + + uint8_t cwc_buf[256]; + int cwc_bufptr; + + /* From configuration */ + + uint8_t cwc_confedkey[14]; + const char *cwc_username; + const char *cwc_password; /* salted version */ + + dtimer_t cwc_idle_timer; + + dtimer_t cwc_send_ka_timer; +} cwc_t; + +static LIST_HEAD(, cwc) cwcs; + + + +/** + * + */ +static void +des_key_parity_adjust(uint8_t *key, uint8_t len) +{ + uint8_t i, j, parity; + + for (i = 0; i < len; i++) { + parity = 1; + for (j = 1; j < 8; j++) if ((key[i] >> j) & 0x1) parity = ~parity & 0x01; + key[i] |= parity; + } +} + + +/** + * + */ +static uint8_t * +des_key_spread(uint8_t *normal) +{ + static uint8_t spread[16]; + + spread[ 0] = normal[ 0] & 0xfe; + spread[ 1] = ((normal[ 0] << 7) | (normal[ 1] >> 1)) & 0xfe; + spread[ 2] = ((normal[ 1] << 6) | (normal[ 2] >> 2)) & 0xfe; + spread[ 3] = ((normal[ 2] << 5) | (normal[ 3] >> 3)) & 0xfe; + spread[ 4] = ((normal[ 3] << 4) | (normal[ 4] >> 4)) & 0xfe; + spread[ 5] = ((normal[ 4] << 3) | (normal[ 5] >> 5)) & 0xfe; + spread[ 6] = ((normal[ 5] << 2) | (normal[ 6] >> 6)) & 0xfe; + spread[ 7] = normal[ 6] << 1; + spread[ 8] = normal[ 7] & 0xfe; + spread[ 9] = ((normal[ 7] << 7) | (normal[ 8] >> 1)) & 0xfe; + spread[10] = ((normal[ 8] << 6) | (normal[ 9] >> 2)) & 0xfe; + spread[11] = ((normal[ 9] << 5) | (normal[10] >> 3)) & 0xfe; + spread[12] = ((normal[10] << 4) | (normal[11] >> 4)) & 0xfe; + spread[13] = ((normal[11] << 3) | (normal[12] >> 5)) & 0xfe; + spread[14] = ((normal[12] << 2) | (normal[13] >> 6)) & 0xfe; + spread[15] = normal[13] << 1; + + des_key_parity_adjust(spread, 16); + return spread; +} + +/** + * + */ +static void +des_random_get(uint8_t *buffer, uint8_t len) +{ + uint8_t idx = 0; + int randomNo = 0; + + for (idx = 0; idx < len; idx++) { + if (!(idx % 3)) randomNo = rand(); + buffer[idx] = (randomNo >> ((idx % 3) << 3)) & 0xff; + } +} + +/** + * + */ +static int +des_encrypt(uint8_t *buffer, int len, uint8_t *deskey) +{ + uint8_t checksum = 0; + uint8_t noPadBytes; + uint8_t padBytes[7]; + char ivec[8]; + uint16_t i; + + if (!deskey) return len; + noPadBytes = (8 - ((len - 1) % 8)) % 8; + if (len + noPadBytes + 1 >= CWS_NETMSGSIZE-8) return -1; + des_random_get(padBytes, noPadBytes); + for (i = 0; i < noPadBytes; i++) buffer[len++] = padBytes[i]; + for (i = 2; i < len; i++) checksum ^= buffer[i]; + buffer[len++] = checksum; + des_random_get((uint8_t *)ivec, 8); + memcpy(buffer+len, ivec, 8); + for (i = 2; i < len; i += 8) { + cbc_crypt((char *)deskey , (char *) buffer+i, 8, DES_ENCRYPT, ivec); + ecb_crypt((char *)deskey+8, (char *) buffer+i, 8, DES_DECRYPT); + ecb_crypt((char *)deskey , (char *) buffer+i, 8, DES_ENCRYPT); + memcpy(ivec, buffer+i, 8); + } + len += 8; + return len; +} + +/** + * + */ +static int +des_decrypt(uint8_t *buffer, int len, uint8_t *deskey) +{ + char ivec[8]; + char nextIvec[8]; + int i; + uint8_t checksum = 0; + + if (!deskey) return len; + if ((len-2) % 8 || (len-2) < 16) return -1; + len -= 8; + memcpy(nextIvec, buffer+len, 8); + for (i = 2; i < len; i += 8) + { + memcpy(ivec, nextIvec, 8); + memcpy(nextIvec, buffer+i, 8); + ecb_crypt((char *)deskey , (char *) buffer+i, 8, DES_DECRYPT); + ecb_crypt((char *)deskey+8, (char *) buffer+i, 8, DES_ENCRYPT); + cbc_crypt((char *)deskey , (char *) buffer+i, 8, DES_DECRYPT, ivec); + } + for (i = 2; i < len; i++) checksum ^= buffer[i]; + if (checksum) return -1; + return len; +} + +/** + * + */ +static void +des_make_login_key(cwc_t *cwc, uint8_t *k) +{ + uint8_t des14[14]; + int i; + + for (i = 0; i < 14; i++) + des14[i] = cwc->cwc_confedkey[i] ^ k[i]; + memcpy(cwc->cwc_key, des_key_spread(des14), 16); +} + +/** + * + */ +static void +des_make_session_key(cwc_t *cwc) +{ + uint8_t des14[14], *k2 = (uint8_t *)cwc->cwc_password; + int i, l = strlen(cwc->cwc_password); + + memcpy(des14, cwc->cwc_confedkey, 14); + + for (i = 0; i < l; i++) + des14[i % 14] ^= k2[i]; + + memcpy(cwc->cwc_key, des_key_spread(des14), 16); +} + + +/** + * + */ +static void +cwc_timeout(void *aux, int64_t now) +{ + cwc_t *cwc = aux; + tcp_disconnect(&cwc->cwc_tcp_session, ETIMEDOUT); +} + + +/** + * + */ +static int +cwc_send_msg(cwc_t *cwc, const uint8_t *msg, size_t len, int sid) +{ + tcp_session_t *ses = &cwc->cwc_tcp_session; + + uint8_t *buf = malloc(CWS_NETMSGSIZE); + + memset(buf, 0, 12); + memcpy(buf + 12, msg, len); + + len += 12; + + cwc->cwc_seq++; + + buf[2] = cwc->cwc_seq >> 8; + buf[3] = cwc->cwc_seq; + buf[4] = sid >> 8; + buf[5] = sid; + + if((len = des_encrypt(buf, len, cwc->cwc_key)) < 0) { + free(buf); + return -1; + } + + buf[0] = (len - 2) >> 8; + buf[1] = len - 2; + + tcp_send_msg(ses, &ses->tcp_q_hi, buf, len); + + /* Expect a response within 4 seconds */ + dtimer_arm(&cwc->cwc_idle_timer, cwc_timeout, cwc, 4); + return cwc->cwc_seq; +} + + + +/** + * Card data command + */ +static void +cwc_send_data_req(cwc_t *cwc) +{ + uint8_t buf[CWS_NETMSGSIZE]; + + cwc->cwc_state = CWC_STATE_WAIT_CARD_DATA; + + buf[0] = MSG_CARD_DATA_REQ; + buf[1] = 0; + buf[2] = 0; + + cwc_send_msg(cwc, buf, 3, 0); +} + + +/** + * Send keep alive + */ +static void +cwc_send_ka(void *aux, int64_t now) +{ + cwc_t *cwc = aux; + uint8_t buf[CWS_NETMSGSIZE]; + + buf[0] = MSG_KEEPALIVE; + buf[1] = 0; + buf[2] = 0; + + cwc_send_msg(cwc, buf, 3, 0); + dtimer_arm(&cwc->cwc_send_ka_timer, cwc_send_ka, cwc, + CWC_KEEPALIVE_INTERVAL); +} + + +/** + * Handle reply to card data request + */ +static int +cwc_dispatch_card_data_reply(cwc_t *cwc, uint8_t msgtype, + uint8_t *msg, int len) +{ + int plen; + const char *n; + + if(msgtype != MSG_CARD_DATA) + return EBADMSG; + + msg += 12; + len -= 12; + plen = (msg[1] & 0xf) << 8 | msg[2]; + + if(plen < 14) + return EBADMSG; + + cwc->cwc_caid = (msg[4] << 8) | msg[5]; + n = psi_caid2name(cwc->cwc_caid) ?: "Unknown"; + + syslog(LOG_INFO, "cwc: %s: Connected as user 0x%02x " + "to a %s-card [0x%04x : %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x] " + "with %d providers", + cwc->cwc_tcp_session.tcp_hostname, + msg[3], n, cwc->cwc_caid, + msg[6], msg[7], msg[8], msg[9], msg[10], msg[11], msg[12], msg[13], + msg[14]); + + cwc->cwc_state = CWC_STATE_RUNNING; + + /* Send KA every CWC_KEEPALIVE_INTERVAL seconds */ + + dtimer_arm(&cwc->cwc_send_ka_timer, cwc_send_ka, cwc, + CWC_KEEPALIVE_INTERVAL); + + return 0; +} + + +/** + * Login command + */ +static void +cwc_send_login(cwc_t *cwc) +{ + uint8_t buf[CWS_NETMSGSIZE]; + int ul = strlen(cwc->cwc_username) + 1; + int pl = strlen(cwc->cwc_password) + 1; + + cwc->cwc_state = CWC_STATE_WAIT_LOGIN_ACK; + + buf[0] = MSG_CLIENT_2_SERVER_LOGIN; + buf[1] = 0; + buf[2] = ul + pl; + memcpy(buf + 3, cwc->cwc_username, ul); + memcpy(buf + 3 + ul, cwc->cwc_password, pl); + + cwc_send_msg(cwc, buf, ul + pl + 3, 0); +} + + +/** + * Handle reply to login + */ +static int +cwc_dispatch_login_reply(cwc_t *cwc, uint8_t msgtype, uint8_t *msg, int len) +{ + switch(msgtype) { + case MSG_CLIENT_2_SERVER_LOGIN_ACK: + des_make_session_key(cwc); + cwc_send_data_req(cwc); + return 0; + + case MSG_CLIENT_2_SERVER_LOGIN_NAK: + return EACCES; + + default: + return EBADMSG; + } +} + + +/** + * Handle reply to login + */ +static int +cwc_dispatch_running_reply(cwc_t *cwc, uint8_t msgtype, uint8_t *msg, int len) +{ + cwc_transport_t *ct; + uint16_t seq = (msg[2] << 8) | msg[3]; + th_transport_t *t; + + len -= 12; + msg += 12; + + switch(msgtype) { + case 0x80: + case 0x81: + LIST_FOREACH(ct, &cwc_pending_requests, ct_link) { + if(ct->ct_seq == seq) + break; + } + + printf("got key response, ct = %p, len = %d\n", ct, len); + + if(ct == NULL) + return 0; + + t = ct->ct_transport; + + LIST_REMOVE(ct, ct_link); + ct->ct_pending = 0; + + if(len < 19) { + + if(ct->ct_keystate != CT_FORBIDDEN) + syslog(LOG_ERR, + "Cannot descramble \"%s\" for channel \"%s\", access denied", + t->tht_uniquename, t->tht_channel->ch_name); + + ct->ct_keystate = CT_FORBIDDEN; + return 0; + } + + if(ct->ct_keystate != CT_RESOLVED) + syslog(LOG_INFO, + "Obtained key for \"%s\" for channel \"%s\"", + t->tht_uniquename, t->tht_channel->ch_name); + + ct->ct_keystate = CT_RESOLVED; + set_control_words(ct->ct_keys, msg + 3, msg + 3 + 8); + break; + } + return 0; +} + + +/** + * + */ +static void +cwc_data_input(cwc_t *cwc) +{ + int msglen, r; + tcp_session_t *ses = &cwc->cwc_tcp_session; + int fd = ses->tcp_fd; + + if(cwc->cwc_state == CWC_STATE_WAIT_LOGIN_KEY) { + + r = read(fd, cwc->cwc_buf + cwc->cwc_bufptr, 14 - cwc->cwc_bufptr); + if(r < 1) { + tcp_disconnect(ses, r == 0 ? ECONNRESET : errno); + return; + } + + cwc->cwc_bufptr += r; + if(cwc->cwc_bufptr < 14) + return; + + des_make_login_key(cwc, cwc->cwc_buf); + cwc_send_login(cwc); + cwc->cwc_bufptr = 0; + + } else { + + if(cwc->cwc_bufptr < 2) { + msglen = 2; + } else { + msglen = ((cwc->cwc_buf[0] << 8) | cwc->cwc_buf[1]) + 2; + if(msglen >= CWS_NETMSGSIZE) { + tcp_disconnect(ses, EMSGSIZE); + return; + } + } + + r = read(fd, cwc->cwc_buf + cwc->cwc_bufptr, msglen - cwc->cwc_bufptr); + if(r < 1) { + tcp_disconnect(ses, r == 0 ? ECONNRESET : errno); + return; + } + + cwc->cwc_bufptr += r; + + if(msglen > 2 && cwc->cwc_bufptr == msglen) { + if((msglen = des_decrypt(cwc->cwc_buf, msglen, cwc->cwc_key)) < 15) { + tcp_disconnect(ses, EILSEQ); + return; + } + cwc->cwc_bufptr = 0; + + switch(cwc->cwc_state) { + case CWC_STATE_WAIT_LOGIN_ACK: + r = cwc_dispatch_login_reply(cwc, cwc->cwc_buf[12], + cwc->cwc_buf, msglen); + break; + + case CWC_STATE_WAIT_CARD_DATA: + r = cwc_dispatch_card_data_reply(cwc, cwc->cwc_buf[12], + cwc->cwc_buf, msglen); + break; + + case CWC_STATE_RUNNING: + r = cwc_dispatch_running_reply(cwc, cwc->cwc_buf[12], + cwc->cwc_buf, msglen); + break; + + default: + r = EBADMSG; + break; + } + + if(r != 0) { + tcp_disconnect(ses, r); + return; + } + } + } +} + + + +/** + * + */ +static void +cwc_tcp_callback(tcpevent_t event, void *tcpsession) +{ + cwc_t *cwc = tcpsession; + + dtimer_disarm(&cwc->cwc_idle_timer); + + switch(event) { + case TCP_CONNECT: + cwc->cwc_seq = 0; + cwc->cwc_bufptr = 0; + cwc->cwc_state = CWC_STATE_WAIT_LOGIN_KEY; + /* We want somthing within 20 seconds */ + dtimer_arm(&cwc->cwc_idle_timer, cwc_timeout, cwc, 20); + break; + + case TCP_DISCONNECT: + cwc->cwc_state = CWC_STATE_IDLE; + dtimer_disarm(&cwc->cwc_send_ka_timer); + break; + + case TCP_INPUT: + cwc_data_input(cwc); + break; + } +} + + +/** + * + */ +void +cwc_table_input(struct th_descrambler *td, struct th_transport *t, + struct th_stream *st, uint8_t *data, int len) +{ + cwc_transport_t *ct = (cwc_transport_t *)td; + uint16_t sid = t->tht_dvb_service_id; + cwc_t *cwc = ct->ct_cwc; + + if(cwc->cwc_caid != st->st_caid) + return; + + if((data[0] & 0xf0) != 0x80) + return; + + printf("cwc table %x\n", data[0]); + + switch(data[0]) { + case 0x80: + case 0x81: + /* ECM */ + + if(ct->ct_pending) + return; + + if(ct->ct_ecmsize == len && !memcmp(ct->ct_ecm, data, len)) + return; /* key already sent */ + + if(cwc->cwc_state != CWC_STATE_RUNNING) { + /* New key, but we are not connected (anymore), can not descramble */ + ct->ct_keystate = CT_UNKNOWN; + break; + } + + memcpy(ct->ct_ecm, data, len); + ct->ct_ecmsize = len; + printf("Key xmitted\n"); + ct->ct_seq = cwc_send_msg(cwc, data, len, sid); + LIST_INSERT_HEAD(&cwc_pending_requests, ct, ct_link); + ct->ct_pending = 1; + break; + + default: + /* EMM */ + cwc_send_msg(cwc, data, len, sid); + break; + } +} + + +/** + * + */ +static int +cwc_descramble(th_descrambler_t *td, th_transport_t *t, struct th_stream *st, + uint8_t *tsb) +{ + cwc_transport_t *ct = (cwc_transport_t *)td; + int r, i; + unsigned char *vec[3]; + uint8_t *t0; + + if(ct->ct_keystate != CT_RESOLVED) + return 0; + + memcpy(ct->ct_tsbcluster + ct->ct_fill * 188, tsb, 188); + ct->ct_fill++; + + if(ct->ct_fill != CT_CLUSTER_SIZE) + return 1; + + ct->ct_fill = 0; + + vec[0] = ct->ct_tsbcluster; + vec[1] = ct->ct_tsbcluster + CT_CLUSTER_SIZE * 188; + vec[2] = NULL; + + while(1) { + t0 = vec[0]; + r = decrypt_packets(ct->ct_keys, vec); + if(r == 0) + break; + for(i = 0; i < r; i++) { + ts_recv_packet(t, (t0[1] & 0x1f) << 8 | t0[2], t0, 0); + t0 += 188; + } + } + return 1; +} + + +/** + * + */ +static void +cwc_transport_stop(th_descrambler_t *td) +{ + cwc_transport_t *ct = (cwc_transport_t *)td; + + if(ct->ct_pending) + LIST_REMOVE(ct, ct_link); + + LIST_REMOVE(ct, ct_cwc_link); + + LIST_REMOVE(td, td_transport_link); + free_key_struct(ct->ct_keys); + free(ct); +} + + +/** + * Check if our CAID's matches, and if so, link + */ +void +cwc_transport_start(th_transport_t *t) +{ + cwc_t *cwc; + cwc_transport_t *ct; + th_descrambler_t *td; + + LIST_FOREACH(cwc, &cwcs, cwc_link) { + ct = calloc(1, sizeof(cwc_transport_t)); + ct->ct_keys = get_key_struct(); + ct->ct_cwc = cwc; + ct->ct_transport = t; + LIST_INSERT_HEAD(&cwc->cwc_transports, ct, ct_cwc_link); + td = &ct->ct_head; + + td->td_stop = cwc_transport_stop; + td->td_table = cwc_table_input; + td->td_descramble = cwc_descramble; + LIST_INSERT_HEAD(&t->tht_descramblers, td, td_transport_link); + printf("descrambler created\n"); + } +} + + +/** + * + */ +static int +nibble(char c) +{ + switch(c) { + case '0' ... '9': + return c - '0'; + case 'a' ... 'f': + return c - 'a' + 10; + case 'A' ... 'F': + return c - 'A' + 10; + default: + return 0; + } +} + + +/** + * + */ +void +cwc_init(void) +{ + cwc_t *cwc; + void *iterator = NULL, *head; + const char *username; + const char *password; + const char *deskey, *k; + const char *hostname; + int port; + uint8_t key[14]; + int i, u, l; + + while((head = config_iterate_sections(&iterator, "cwc")) != NULL) { + + if((hostname = config_get_str_sub(head, "hostname", NULL)) == NULL) { + syslog(LOG_INFO, "cwc: config section missing 'hostname'"); + } + + if((port = atoi(config_get_str_sub(head, "port", "0"))) == 0) { + syslog(LOG_INFO, "cwc: config section missing 'port'"); + } + + if((username = config_get_str_sub(head, "username", NULL)) == NULL) { + syslog(LOG_INFO, "cwc: config section missing 'username'"); + } + + if((password = config_get_str_sub(head, "password", NULL)) == NULL) { + syslog(LOG_INFO, "cwc: config section missing 'password'"); + } + + if((deskey = config_get_str_sub(head, "deskey", NULL)) == NULL) { + syslog(LOG_INFO, "cwc: config section missing 'deskey'"); + } + + + k = deskey; + for(i = 0; i < 14; i++) { + while(*k != 0 && !isxdigit(*k)) k++; + if(*k == 0) + break; + u = nibble(*k++); + while(*k != 0 && !isxdigit(*k)) k++; + if(*k == 0) + break; + l = nibble(*k++); + key[i] = (u << 4) | l; + } + + if(i != 14) { + syslog(LOG_INFO, "cwc: 'deskey' is not 14 valid hexadecimal bytes"); + continue; + } + + if(hostname == NULL || username == NULL || password == NULL || + deskey == NULL || port == 0) + continue; + + cwc = tcp_create_client(hostname, port, sizeof(cwc_t), + "cwc", cwc_tcp_callback); + + cwc->cwc_username = strdup(username); + + if(!strncmp(password, "$1$", 3)) { + cwc->cwc_password = strdup(password); + } else { + cwc->cwc_password = strdup(cwc_krypt(password, "$1$abcdefgh$")); + } + + memcpy(cwc->cwc_confedkey, key, 14); + LIST_INSERT_HEAD(&cwcs, cwc, cwc_link); + + } +} diff --git a/cwc.h b/cwc.h new file mode 100644 index 00000000..afcf5ab3 --- /dev/null +++ b/cwc.h @@ -0,0 +1,26 @@ +/* + * tvheadend, CWC interface + * Copyright (C) 2007 Andreas Öman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CWC_H_ +#define CWC_H_ + +void cwc_init(void); + +void cwc_transport_start(th_transport_t *t); + +#endif /* CWC_H_ */ diff --git a/ffdecsa/FFdecsa.c b/ffdecsa/FFdecsa.c new file mode 100644 index 00000000..ffc5147d --- /dev/null +++ b/ffdecsa/FFdecsa.c @@ -0,0 +1,880 @@ +/* FFdecsa -- fast decsa algorithm + * + * Copyright (C) 2003-2004 fatih89r + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include +#include +#include +#include + +#include "FFdecsa.h" + +#ifndef NULL +#define NULL 0 +#endif + +//#define DEBUG +#ifdef DEBUG +#define DBG(a) a +#else +#define DBG(a) +#endif + +//// parallelization stuff, large speed differences are possible +// possible choices +#define PARALLEL_32_4CHAR 320 +#define PARALLEL_32_4CHARA 321 +#define PARALLEL_32_INT 322 +#define PARALLEL_64_8CHAR 640 +#define PARALLEL_64_8CHARA 641 +#define PARALLEL_64_2INT 642 +#define PARALLEL_64_LONG 643 +#define PARALLEL_64_MMX 644 +#define PARALLEL_128_16CHAR 1280 +#define PARALLEL_128_16CHARA 1281 +#define PARALLEL_128_4INT 1282 +#define PARALLEL_128_2LONG 1283 +#define PARALLEL_128_2MMX 1284 +#define PARALLEL_128_SSE 1285 +#define PARALLEL_128_SSE2 1286 + +//////// our choice //////////////// our choice //////////////// our choice //////////////// our choice //////// +#ifndef PARALLEL_MODE +#define PARALLEL_MODE PARALLEL_64_MMX +#endif +//////// our choice //////////////// our choice //////////////// our choice //////////////// our choice //////// + +#include "parallel_generic.h" +//// conditionals +#if PARALLEL_MODE==PARALLEL_32_4CHAR +#include "parallel_032_4char.h" +#elif PARALLEL_MODE==PARALLEL_32_4CHARA +#include "parallel_032_4charA.h" +#elif PARALLEL_MODE==PARALLEL_32_INT +#include "parallel_032_int.h" +#elif PARALLEL_MODE==PARALLEL_64_8CHAR +#include "parallel_064_8char.h" +#elif PARALLEL_MODE==PARALLEL_64_8CHARA +#include "parallel_064_8charA.h" +#elif PARALLEL_MODE==PARALLEL_64_2INT +#include "parallel_064_2int.h" +#elif PARALLEL_MODE==PARALLEL_64_LONG +#include "parallel_064_long.h" +#elif PARALLEL_MODE==PARALLEL_64_MMX +#include "parallel_064_mmx.h" +#elif PARALLEL_MODE==PARALLEL_128_16CHAR +#include "parallel_128_16char.h" +#elif PARALLEL_MODE==PARALLEL_128_16CHARA +#include "parallel_128_16charA.h" +#elif PARALLEL_MODE==PARALLEL_128_4INT +#include "parallel_128_4int.h" +#elif PARALLEL_MODE==PARALLEL_128_2LONG +#include "parallel_128_2long.h" +#elif PARALLEL_MODE==PARALLEL_128_2MMX +#include "parallel_128_2mmx.h" +#elif PARALLEL_MODE==PARALLEL_128_SSE +#include "parallel_128_sse.h" +#elif PARALLEL_MODE==PARALLEL_128_SSE2 +#include "parallel_128_sse2.h" +#else +#error "unknown/undefined parallel mode" +#endif + +// stuff depending on conditionals + +#define BYTES_PER_GROUP (GROUP_PARALLELISM/8) +#define BYPG BYTES_PER_GROUP +#define BITS_PER_GROUP GROUP_PARALLELISM +#define BIPG BITS_PER_GROUP + +#ifndef MALLOC +#define MALLOC(X) malloc(X) +#endif +#ifndef FREE +#define FREE(X) free(X) +#endif +#ifndef MEMALIGN +#define MEMALIGN +#endif + +//// debug tool + +#if 0 +static void dump_mem(const char *string, const unsigned char *p, int len, int linelen){ + int i; + for(i=0;i>4)&0xf; + iA[1]=(ck[0] )&0xf; + iA[2]=(ck[1]>>4)&0xf; + iA[3]=(ck[1] )&0xf; + iA[4]=(ck[2]>>4)&0xf; + iA[5]=(ck[2] )&0xf; + iA[6]=(ck[3]>>4)&0xf; + iA[7]=(ck[3] )&0xf; + iB[0]=(ck[4]>>4)&0xf; + iB[1]=(ck[4] )&0xf; + iB[2]=(ck[5]>>4)&0xf; + iB[3]=(ck[5] )&0xf; + iB[4]=(ck[6]>>4)&0xf; + iB[5]=(ck[6] )&0xf; + iB[6]=(ck[7]>>4)&0xf; + iB[7]=(ck[7] )&0xf; +} + +//----- stream main function + +#define STREAM_INIT +#include "stream.c" +#undef STREAM_INIT + +#define STREAM_NORMAL +#include "stream.c" +#undef STREAM_NORMAL + + +//-----block decypher + +//-----key schedule for block decypher + +static void key_schedule_block( + unsigned char *ck, // [In] ck[0]-ck[7] 8 bytes | Key. + unsigned char *kk) // [Out] kk[0]-kk[55] 56 bytes | Key schedule. +{ + static const unsigned char key_perm[0x40] = { + 0x12,0x24,0x09,0x07,0x2A,0x31,0x1D,0x15, 0x1C,0x36,0x3E,0x32,0x13,0x21,0x3B,0x40, + 0x18,0x14,0x25,0x27,0x02,0x35,0x1B,0x01, 0x22,0x04,0x0D,0x0E,0x39,0x28,0x1A,0x29, + 0x33,0x23,0x34,0x0C,0x16,0x30,0x1E,0x3A, 0x2D,0x1F,0x08,0x19,0x17,0x2F,0x3D,0x11, + 0x3C,0x05,0x38,0x2B,0x0B,0x06,0x0A,0x2C, 0x20,0x3F,0x2E,0x0F,0x03,0x26,0x10,0x37, + }; + + int i,j,k; + int bit[64]; + int newbit[64]; + int kb[7][8]; + + // 56 steps + // 56 key bytes kk(55)..kk(0) by key schedule from ck + + // kb(6,0) .. kb(6,7) = ck(0) .. ck(7) + kb[6][0] = ck[0]; + kb[6][1] = ck[1]; + kb[6][2] = ck[2]; + kb[6][3] = ck[3]; + kb[6][4] = ck[4]; + kb[6][5] = ck[5]; + kb[6][6] = ck[6]; + kb[6][7] = ck[7]; + + // calculate kb[5] .. kb[0] + for(i=5; i>=0; i--){ + // 64 bit perm on kb + for(j=0; j<8; j++){ + for(k=0; k<8; k++){ + bit[j*8+k] = (kb[i+1][j] >> (7-k)) & 1; + newbit[key_perm[j*8+k]-1] = bit[j*8+k]; + } + } + for(j=0; j<8; j++){ + kb[i][j] = 0; + for(k=0; k<8; k++){ + kb[i][j] |= newbit[j*8+k] << (7-k); + } + } + } + + // xor to give kk + for(i=0; i<7; i++){ + for(j=0; j<8; j++){ + kk[i*8+j] = kb[i][j] ^ i; + } + } + +} + +//-----block utils + +static inline __attribute__((always_inline)) void trasp_N_8 (unsigned char *in,unsigned char* out,int count){ + int *ri=(int *)in; + int *ibi=(int *)out; + int j,i,k,g; + // copy and first step + for(g=0;g>16) | (b&0xffff0000) ; + } + } + } +//dump_mem("NE2 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); +// now 01010101 + for(j=0;j<8;j+=2){ + for(i=0;i<1;i++){ + for(k=0;k>8) | (b&0xff00ff00); + } + } + } +//dump_mem("NE3 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); +// now 00000000 +} + +static inline __attribute__((always_inline)) void trasp_8_N (unsigned char *in,unsigned char* out,int count){ + int *ri=(int *)in; + int *bdi=(int *)out; + int j,i,k,g; +#define INTS_PER_ROW (GROUP_PARALLELISM/8*2) +//dump_mem("NE1 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); +// now 00000000 + for(j=0;j<8;j+=2){ + for(i=0;i<1;i++){ + for(k=0;k>8) | (b&0xff00ff00); + } + } + } +//dump_mem("NE2 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); +// now 01010101 + for(j=0;j<8;j+=4){ + for(i=0;i<2;i++){ + for(k=0;k>16) | (b&0xffff0000) ; + } + } + } +//dump_mem("NE3 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); +// now 01230123 + for(g=0;g=0;i--){ + { + MEMALIGN batch tkkmulti=kkmulti[i]; + batch *si=(batch *)sbox_in; + batch *r6_N=(batch *)(r+roff+GROUP_PARALLELISM*6); + for(g=0;gck,pk,8); +// precalculations for stream + key_schedule_stream(key->ck,key->iA,key->iB); + for(by=0;by<8;by++){ + for(bi=0;bi<8;bi++){ + key->ck_g[by][bi]=(key->ck[by]&(1<iA_g[by][bi]=(key->iA[by]&(1<iB_g[by][bi]=(key->iB[by]&(1<ck,key->kk); + for(i=0;i<56;i++){ + for(j=0;jkkmulti[i])+j)=key->kk[i]; + } + } +} + +void set_control_words(void *keys, const unsigned char *ev, const unsigned char *od){ + schedule_key(&((struct csa_keys_t *)keys)->even,ev); + schedule_key(&((struct csa_keys_t *)keys)->odd,od); +} + +void set_even_control_word(void *keys, const unsigned char *pk){ + schedule_key(&((struct csa_keys_t *)keys)->even,pk); +} + +void set_odd_control_word(void *keys, const unsigned char *pk){ + schedule_key(&((struct csa_keys_t *)keys)->odd,pk); +} + +//-----get control words + +void get_control_words(void *keys, unsigned char *even, unsigned char *odd){ + memcpy(even,&((struct csa_keys_t *)keys)->even.ck,8); + memcpy(odd,&((struct csa_keys_t *)keys)->odd.ck,8); +} + +//----- decrypt + +int decrypt_packets(void *keys, unsigned char **cluster){ + // statistics, currently unused + int stat_no_scramble=0; + int stat_reserved=0; + int stat_decrypted[2]={0,0}; + int stat_decrypted_mini=0; + unsigned char **clst; + unsigned char **clst2; + int grouped; + int group_ev_od; + int advanced; + int can_advance; + unsigned char *g_pkt[GROUP_PARALLELISM]; + int g_len[GROUP_PARALLELISM]; + int g_offset[GROUP_PARALLELISM]; + int g_n[GROUP_PARALLELISM]; + int g_residue[GROUP_PARALLELISM]; + unsigned char *pkt; + int xc0,ev_od,len,offset,n,residue; + struct csa_key_t* k; + int i,j,iter,g; + int t23,tsmall; + int alive[24]; +//icc craziness int pad1=0; //////////align! FIXME + unsigned char *encp[GROUP_PARALLELISM]; + unsigned char stream_in[GROUP_PARALLELISM*8]; + unsigned char stream_out[GROUP_PARALLELISM*8]; + MEMALIGN unsigned char ib[GROUP_PARALLELISM*8]; + MEMALIGN unsigned char block_out[GROUP_PARALLELISM*8]; + struct stream_regs regs; + +//icc craziness i=(int)&pad1;//////////align!!! FIXME + + // build a list of packets to be processed + clst=cluster; + grouped=0; + advanced=0; + can_advance=1; + group_ev_od=-1; // silence incorrect compiler warning + pkt=*clst; + do{ // find a new packet + if(grouped==GROUP_PARALLELISM){ + // full + break; + } + if(pkt==NULL){ + // no more ranges + break; + } + if(pkt>=*(clst+1)){ + // out of this range, try next + clst++;clst++; + pkt=*clst; + continue; + } + + do{ // handle this packet + xc0=pkt[3]&0xc0; + DBG(fprintf(stderr," exam pkt=%p, xc0=%02x, can_adv=%i\n",pkt,xc0,can_advance)); + if(xc0==0x00){ + DBG(fprintf(stderr,"skip clear pkt %p (can_advance is %i)\n",pkt,can_advance)); + advanced+=can_advance; + stat_no_scramble++; + break; + } + if(xc0==0x40){ + DBG(fprintf(stderr,"skip reserved pkt %p (can_advance is %i)\n",pkt,can_advance)); + advanced+=can_advance; + stat_reserved++; + break; + } + if(xc0==0x80||xc0==0xc0){ // encrypted + ev_od=(xc0&0x40)>>6; // 0 even, 1 odd + if(grouped==0) group_ev_od=ev_od; // this group will be all even (or odd) + if(group_ev_od==ev_od){ // could be added to group + pkt[3]&=0x3f; // consider it decrypted now + if(pkt[3]&0x20){ // incomplete packet + offset=4+pkt[4]+1; + len=188-offset; + n=len>>3; + residue=len-(n<<3); + if(n==0){ // decrypted==encrypted! + DBG(fprintf(stderr,"DECRYPTED MINI! (can_advance is %i)\n",can_advance)); + advanced+=can_advance; + stat_decrypted_mini++; + break; // this doesn't need more processing + } + }else{ + len=184; + offset=4; + n=23; + residue=0; + } + g_pkt[grouped]=pkt; + g_len[grouped]=len; + g_offset[grouped]=offset; + g_n[grouped]=n; + g_residue[grouped]=residue; + DBG(fprintf(stderr,"%2i: eo=%i pkt=%p len=%03i n=%2i residue=%i\n",grouped,ev_od,pkt,len,n,residue)); + grouped++; + advanced+=can_advance; + stat_decrypted[ev_od]++; + } + else{ + can_advance=0; + DBG(fprintf(stderr,"skip pkt %p and can_advance set to 0\n",pkt)); + break; // skip and go on + } + } + } while(0); + + if(can_advance){ + // move range start forward + *clst+=188; + } + // next packet, if there is one + pkt+=188; + } while(1); + DBG(fprintf(stderr,"-- result: grouped %i pkts, advanced %i pkts\n",grouped,advanced)); + + // delete empty ranges and compact list + clst2=cluster; + for(clst=cluster;*clst!=NULL;clst+=2){ + // if not empty + if(*clst<*(clst+1)){ + // it will remain + *clst2=*clst; + *(clst2+1)=*(clst+1); + clst2+=2; + } + } + *clst2=NULL; + + if(grouped==0){ + // no processing needed + return advanced; + } + + // sort them, longest payload first + // we expect many n=23 packets and a few n<23 + DBG(fprintf(stderr,"PRESORTING\n")); + for(i=0;i=0;tsmall--){ + if(g_n[tsmall]==23) break; + } +DBG(fprintf(stderr,"tsmall after for =%i\n",tsmall)); + + if(tsmall-t23<1) break; + +DBG(fprintf(stderr,"swap t23=%i,tsmall=%i\n",t23,tsmall)); + + g_swap(t23,tsmall); + + t23++; + tsmall--; +DBG(fprintf(stderr,"new t23=%i,tsmall=%i\n\n",t23,tsmall)); + } + DBG(fprintf(stderr,"packets with n=23, t23=%i grouped=%i\n",t23,grouped)); + DBG(fprintf(stderr,"MIDSORTING\n")); + for(i=0;ig_n[i]){ + g_swap(i,j); + } + } + } + DBG(fprintf(stderr,"POSTSORTING\n")); + for(i=0;i=0;i--){ + alive[i]+=alive[i+1]; + } + DBG(fprintf(stderr,"ALIVE\n")); + for(i=0;i<=23;i++){ + DBG(fprintf(stderr,"alive%2i=%i\n",i,alive[i])); + } + + // choose key + if(group_ev_od==0){ + k=&((struct csa_keys_t *)keys)->even; + } + else{ + k=&((struct csa_keys_t *)keys)->odd; + } + + //INIT +//#define INITIALIZE_UNUSED_INPUT +#ifdef INITIALIZE_UNUSED_INPUT +// unnecessary zeroing. +// without this, we operate on uninitialized memory +// when grouped>>>>ITER 0\n")); + iter=0; + stream_cypher_group_init(®s,k->iA_g,k->iB_g,stream_in); + // fill first ib + for(g=0;g0;iter++){ +DBG(fprintf(stderr,">>>>>ITER %i\n",iter)); + // alive and just dead packets: calc block + block_decypher_group(k->kkmulti,ib,block_out,alive[iter-1]); +DBG(dump_mem("BLO_ib ",block_out,8*alive[iter-1],8)); + // all packets (dead too): calc stream + stream_cypher_group_normal(®s,stream_out); +//dump_mem("stream_out",stream_out,GROUP_PARALLELISM*8,BYPG); + + // alive packets: calc ib + for(g=0;g>>>>ITER 23\n")); + iter=23; + // calc block + block_decypher_group(k->kkmulti,ib,block_out,alive[iter-1]); +DBG(dump_mem("23BLO_ib ",block_out,8*alive[iter-1],8)); + // just dead packets: write decrypted data + for(g=alive[iter];g + +#define MEMALIGN __attribute__((aligned(16))) + +union __u64 { + unsigned int u[2]; + __m64 v; +}; + +static const union __u64 ff0 = {{0x00000000U, 0x00000000U}}; +static const union __u64 ff1 = {{0xffffffffU, 0xffffffffU}}; + +typedef __m64 group; +#define GROUP_PARALLELISM 64 +#define FF0() ff0.v +#define FF1() ff1.v +#define FFAND(a,b) _mm_and_si64((a),(b)) +#define FFOR(a,b) _mm_or_si64((a),(b)) +#define FFXOR(a,b) _mm_xor_si64((a),(b)) +#define FFNOT(a) _mm_xor_si64((a),FF1()) + +/* 64 rows of 64 bits */ + +static const union __u64 ff29 = {{0x29292929U, 0x29292929U}}; +static const union __u64 ff02 = {{0x02020202U, 0x02020202U}}; +static const union __u64 ff04 = {{0x04040404U, 0x04040404U}}; +static const union __u64 ff10 = {{0x10101010U, 0x10101010U}}; +static const union __u64 ff40 = {{0x40404040U, 0x40404040U}}; +static const union __u64 ff80 = {{0x80808080U, 0x80808080U}}; + +typedef __m64 batch; +#define BYTES_PER_BATCH 8 +#define B_FFAND(a,b) FFAND((a),(b)) +#define B_FFOR(a,b) FFOR((a),(b)) +#define B_FFXOR(a,b) FFXOR((a),(b)) +#define B_FFN_ALL_29() ff29.v +#define B_FFN_ALL_02() ff02.v +#define B_FFN_ALL_04() ff04.v +#define B_FFN_ALL_10() ff10.v +#define B_FFN_ALL_40() ff40.v +#define B_FFN_ALL_80() ff80.v +#define B_FFSH8L(a,n) _mm_slli_si64((a),(n)) +#define B_FFSH8R(a,n) _mm_srli_si64((a),(n)) + +#define M_EMPTY() _mm_empty() + + +#undef XOR_8_BY +#define XOR_8_BY(d,s1,s2) do { *(__m64*)d = _mm_xor_si64(*(__m64*)(s1), *(__m64*)(s2)); } while(0) + +#undef XOREQ_8_BY +#define XOREQ_8_BY(d,s) XOR_8_BY(d, d, s) + +#undef COPY_8_BY +#define COPY_8_BY(d,s) do { *(__m64 *)(d) = *(__m64 *)(s); } while(0) + +#undef BEST_SPAN +#define BEST_SPAN 8 + +#undef XOR_BEST_BY +#define XOR_BEST_BY(d,s1,s2) XOR_8_BY(d,s1,s2) + +#include "fftable.h" diff --git a/ffdecsa/parallel_generic.h b/ffdecsa/parallel_generic.h new file mode 100644 index 00000000..2af4c1c3 --- /dev/null +++ b/ffdecsa/parallel_generic.h @@ -0,0 +1,102 @@ +/* FFdecsa -- fast decsa algorithm + * + * Copyright (C) 2003-2004 fatih89r + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + + +#if 0 +//// generics +#define COPY4BY(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \ + *pd = *ps; }while(0) +#define COPY8BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ + *pd = *ps; }while(0) +#define COPY16BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ + *pd = *ps; \ + *(pd+1) = *(ps+1); }while(0) +#define COPY32BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ + *pd = *ps; \ + *(pd+1) = *(ps+1) \ + *(pd+2) = *(ps+2) \ + *(pd+3) = *(ps+3); }while(0) +#define XOR4BY(d,s1,s2) do{ int *pd=(int *)(d), *ps1=(int *)(s1), *ps2=(int *)(s2); \ + *pd = *ps1 ^ *ps2; }while(0) +#define XOR8BY(d,s1,s2) do{ long long int *pd=(long long int *)(d), *ps1=(long long int *)(s1), *ps2=(long long int *)(s2); \ + *pd = *ps1 ^ *ps2; }while(0) +#define XOR16BY(d,s1,s2) do{ long long int *pd=(long long int *)(d), *ps1=(long long int *)(s1), *ps2=(long long int *)(s2); \ + *pd = *ps1 ^ *ps2; \ + *(pd+8) = *(ps1+8) ^ *(ps2+8); }while(0) +#define XOR32BY(d,s1,s2) do{ long long int *pd=(long long int *)(d), *ps1=(long long int *)(s1), *ps2=(long long int *)(s2); \ + *pd = *ps1 ^ *ps2; \ + *(pd+1) = *(ps1+1) ^ *(ps2+1); \ + *(pd+2) = *(ps1+2) ^ *(ps2+2); \ + *(pd+3) = *(ps1+3) ^ *(ps2+3); }while(0) +#define XOR32BV(d,s1,s2) do{ int *const pd=(int *const)(d), *ps1=(const int *const)(s1), *ps2=(const int *const)(s2); \ + int z; \ + for(z=0;z<8;z++){ \ + pd[z]=ps1[z]^ps2[z]; \ + } \ + }while(0) +#define XOREQ4BY(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \ + *pd ^= *ps; }while(0) +#define XOREQ8BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ + *pd ^= *ps; }while(0) +#define XOREQ16BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ + *pd ^= *ps; \ + *(pd+1) ^=*(ps+1); }while(0) +#define XOREQ32BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ + *pd ^= *ps; \ + *(pd+1) ^=*(ps+1); \ + *(pd+2) ^=*(ps+2); \ + *(pd+3) ^=*(ps+3); }while(0) +#define XOREQ32BY4(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \ + *pd ^= *ps; \ + *(pd+1) ^=*(ps+1); \ + *(pd+2) ^=*(ps+2); \ + *(pd+3) ^=*(ps+3); \ + *(pd+4) ^=*(ps+4); \ + *(pd+5) ^=*(ps+5); \ + *(pd+6) ^=*(ps+6); \ + *(pd+7) ^=*(ps+7); }while(0) +#define XOREQ32BV(d,s) do{ unsigned char *pd=(unsigned char *)(d), *ps=(unsigned char *)(s); \ + int z; \ + for(z=0;z<32;z++){ \ + pd[z]^=ps[z]; \ + } \ + }while(0) + +#else +#define XOR_4_BY(d,s1,s2) do{ int *pd=(int *)(d), *ps1=(int *)(s1), *ps2=(int *)(s2); \ + *pd = *ps1 ^ *ps2; }while(0) +#define XOR_8_BY(d,s1,s2) do{ long long int *pd=(long long int *)(d), *ps1=(long long int *)(s1), *ps2=(long long int *)(s2); \ + *pd = *ps1 ^ *ps2; }while(0) +#define XOREQ_4_BY(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \ + *pd ^= *ps; }while(0) +#define XOREQ_8_BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ + *pd ^= *ps; }while(0) +#define COPY_4_BY(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \ + *pd = *ps; }while(0) +#define COPY_8_BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ + *pd = *ps; }while(0) + +#define BEST_SPAN 8 +#define XOR_BEST_BY(d,s1,s2) do{ XOR_8_BY(d,s1,s2); }while(0); +#define XOREQ_BEST_BY(d,s) do{ XOREQ_8_BY(d,s); }while(0); +#define COPY_BEST_BY(d,s) do{ COPY_8_BY(d,s); }while(0); + +#define END_MM do{ }while(0); +#endif diff --git a/ffdecsa/stream.c b/ffdecsa/stream.c new file mode 100644 index 00000000..1bda8521 --- /dev/null +++ b/ffdecsa/stream.c @@ -0,0 +1,906 @@ +/* FFdecsa -- fast decsa algorithm + * + * Copyright (C) 2003-2004 fatih89r + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + + +// define statics only once, when STREAM_INIT +#ifdef STREAM_INIT +struct stream_regs { + group A[32+10][4]; // 32 because we will move back (virtual shift register) + group B[32+10][4]; // 32 because we will move back (virtual shift register) + group X[4]; + group Y[4]; + group Z[4]; + group D[4]; + group E[4]; + group F[4]; + group p; + group q; + group r; + }; + +static inline void trasp64_32_88ccw(unsigned char *data){ +/* 64 rows of 32 bits transposition (bytes transp. - 8x8 rotate counterclockwise)*/ +#define row ((unsigned int *)data) + int i,j; + for(j=0;j<64;j+=32){ + unsigned int t,b; + for(i=0;i<16;i++){ + t=row[j+i]; + b=row[j+16+i]; + row[j+i] = (t&0x0000ffff) | ((b )<<16); + row[j+16+i]=((t )>>16) | (b&0xffff0000) ; + } + } + for(j=0;j<64;j+=16){ + unsigned int t,b; + for(i=0;i<8;i++){ + t=row[j+i]; + b=row[j+8+i]; + row[j+i] = (t&0x00ff00ff) | ((b&0x00ff00ff)<<8); + row[j+8+i] =((t&0xff00ff00)>>8) | (b&0xff00ff00); + } + } + for(j=0;j<64;j+=8){ + unsigned int t,b; + for(i=0;i<4;i++){ + t=row[j+i]; + b=row[j+4+i]; + row[j+i] =((t&0x0f0f0f0f)<<4) | (b&0x0f0f0f0f); + row[j+4+i] = (t&0xf0f0f0f0) | ((b&0xf0f0f0f0)>>4); + } + } + for(j=0;j<64;j+=4){ + unsigned int t,b; + for(i=0;i<2;i++){ + t=row[j+i]; + b=row[j+2+i]; + row[j+i] =((t&0x33333333)<<2) | (b&0x33333333); + row[j+2+i] = (t&0xcccccccc) | ((b&0xcccccccc)>>2); + } + } + for(j=0;j<64;j+=2){ + unsigned int t,b; + for(i=0;i<1;i++){ + t=row[j+i]; + b=row[j+1+i]; + row[j+i] =((t&0x55555555)<<1) | (b&0x55555555); + row[j+1+i] = (t&0xaaaaaaaa) | ((b&0xaaaaaaaa)>>1); + } + } +#undef row +} + +static inline void trasp64_32_88cw(unsigned char *data){ +/* 64 rows of 32 bits transposition (bytes transp. - 8x8 rotate clockwise)*/ +#define row ((unsigned int *)data) + int i,j; + for(j=0;j<64;j+=32){ + unsigned int t,b; + for(i=0;i<16;i++){ + t=row[j+i]; + b=row[j+16+i]; + row[j+i] = (t&0x0000ffff) | ((b )<<16); + row[j+16+i]=((t )>>16) | (b&0xffff0000) ; + } + } + for(j=0;j<64;j+=16){ + unsigned int t,b; + for(i=0;i<8;i++){ + t=row[j+i]; + b=row[j+8+i]; + row[j+i] = (t&0x00ff00ff) | ((b&0x00ff00ff)<<8); + row[j+8+i] =((t&0xff00ff00)>>8) | (b&0xff00ff00); + } + } + for(j=0;j<64;j+=8){ + unsigned int t,b; + for(i=0;i<4;i++){ + t=row[j+i]; + b=row[j+4+i]; + row[j+i] =((t&0xf0f0f0f0)>>4) | (b&0xf0f0f0f0); + row[j+4+i]= (t&0x0f0f0f0f) | ((b&0x0f0f0f0f)<<4); + } + } + for(j=0;j<64;j+=4){ + unsigned int t,b; + for(i=0;i<2;i++){ + t=row[j+i]; + b=row[j+2+i]; + row[j+i] =((t&0xcccccccc)>>2) | (b&0xcccccccc); + row[j+2+i]= (t&0x33333333) | ((b&0x33333333)<<2); + } + } + for(j=0;j<64;j+=2){ + unsigned int t,b; + for(i=0;i<1;i++){ + t=row[j+i]; + b=row[j+1+i]; + row[j+i] =((t&0xaaaaaaaa)>>1) | (b&0xaaaaaaaa); + row[j+1+i]= (t&0x55555555) | ((b&0x55555555)<<1); + } + } +#undef row +} + +//64-64---------------------------------------------------------- +static inline void trasp64_64_88ccw(unsigned char *data){ +/* 64 rows of 64 bits transposition (bytes transp. - 8x8 rotate counterclockwise)*/ +#define row ((unsigned long long int *)data) + int i,j; + for(j=0;j<64;j+=64){ + unsigned long long int t,b; + for(i=0;i<32;i++){ + t=row[j+i]; + b=row[j+32+i]; + row[j+i] = (t&0x00000000ffffffffULL) | ((b )<<32); + row[j+32+i]=((t )>>32) | (b&0xffffffff00000000ULL) ; + } + } + for(j=0;j<64;j+=32){ + unsigned long long int t,b; + for(i=0;i<16;i++){ + t=row[j+i]; + b=row[j+16+i]; + row[j+i] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); + row[j+16+i]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; + } + } + for(j=0;j<64;j+=16){ + unsigned long long int t,b; + for(i=0;i<8;i++){ + t=row[j+i]; + b=row[j+8+i]; + row[j+i] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); + row[j+8+i] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); + } + } + for(j=0;j<64;j+=8){ + unsigned long long int t,b; + for(i=0;i<4;i++){ + t=row[j+i]; + b=row[j+4+i]; + row[j+i] =((t&0x0f0f0f0f0f0f0f0fULL)<<4) | (b&0x0f0f0f0f0f0f0f0fULL); + row[j+4+i] = (t&0xf0f0f0f0f0f0f0f0ULL) | ((b&0xf0f0f0f0f0f0f0f0ULL)>>4); + } + } + for(j=0;j<64;j+=4){ + unsigned long long int t,b; + for(i=0;i<2;i++){ + t=row[j+i]; + b=row[j+2+i]; + row[j+i] =((t&0x3333333333333333ULL)<<2) | (b&0x3333333333333333ULL); + row[j+2+i] = (t&0xccccccccccccccccULL) | ((b&0xccccccccccccccccULL)>>2); + } + } + for(j=0;j<64;j+=2){ + unsigned long long int t,b; + for(i=0;i<1;i++){ + t=row[j+i]; + b=row[j+1+i]; + row[j+i] =((t&0x5555555555555555ULL)<<1) | (b&0x5555555555555555ULL); + row[j+1+i] = (t&0xaaaaaaaaaaaaaaaaULL) | ((b&0xaaaaaaaaaaaaaaaaULL)>>1); + } + } +#undef row +} + +static inline void trasp64_64_88cw(unsigned char *data){ +/* 64 rows of 64 bits transposition (bytes transp. - 8x8 rotate clockwise)*/ +#define row ((unsigned long long int *)data) + int i,j; + for(j=0;j<64;j+=64){ + unsigned long long int t,b; + for(i=0;i<32;i++){ + t=row[j+i]; + b=row[j+32+i]; + row[j+i] = (t&0x00000000ffffffffULL) | ((b )<<32); + row[j+32+i]=((t )>>32) | (b&0xffffffff00000000ULL) ; + } + } + for(j=0;j<64;j+=32){ + unsigned long long int t,b; + for(i=0;i<16;i++){ + t=row[j+i]; + b=row[j+16+i]; + row[j+i] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); + row[j+16+i]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; + } + } + for(j=0;j<64;j+=16){ + unsigned long long int t,b; + for(i=0;i<8;i++){ + t=row[j+i]; + b=row[j+8+i]; + row[j+i] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); + row[j+8+i] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); + } + } + for(j=0;j<64;j+=8){ + unsigned long long int t,b; + for(i=0;i<4;i++){ + t=row[j+i]; + b=row[j+4+i]; + row[j+i] =((t&0xf0f0f0f0f0f0f0f0ULL)>>4) | (b&0xf0f0f0f0f0f0f0f0ULL); + row[j+4+i] = (t&0x0f0f0f0f0f0f0f0fULL) | ((b&0x0f0f0f0f0f0f0f0fULL)<<4); + } + } + for(j=0;j<64;j+=4){ + unsigned long long int t,b; + for(i=0;i<2;i++){ + t=row[j+i]; + b=row[j+2+i]; + row[j+i] =((t&0xccccccccccccccccULL)>>2) | (b&0xccccccccccccccccULL); + row[j+2+i] = (t&0x3333333333333333ULL) | ((b&0x3333333333333333ULL)<<2); + } + } + for(j=0;j<64;j+=2){ + unsigned long long int t,b; + for(i=0;i<1;i++){ + t=row[j+i]; + b=row[j+1+i]; + row[j+i] =((t&0xaaaaaaaaaaaaaaaaULL)>>1) | (b&0xaaaaaaaaaaaaaaaaULL); + row[j+1+i] = (t&0x5555555555555555ULL) | ((b&0x5555555555555555ULL)<<1); + } + } +#undef row +} + +//64-128---------------------------------------------------------- +static inline void trasp64_128_88ccw(unsigned char *data){ +/* 64 rows of 128 bits transposition (bytes transp. - 8x8 rotate counterclockwise)*/ +#define halfrow ((unsigned long long int *)data) + int i,j; + for(j=0;j<64;j+=64){ + unsigned long long int t,b; + for(i=0;i<32;i++){ + t=halfrow[2*(j+i)]; + b=halfrow[2*(j+32+i)]; + halfrow[2*(j+i)] = (t&0x00000000ffffffffULL) | ((b )<<32); + halfrow[2*(j+32+i)]=((t )>>32) | (b&0xffffffff00000000ULL) ; + t=halfrow[2*(j+i)+1]; + b=halfrow[2*(j+32+i)+1]; + halfrow[2*(j+i)+1] = (t&0x00000000ffffffffULL) | ((b )<<32); + halfrow[2*(j+32+i)+1]=((t )>>32) | (b&0xffffffff00000000ULL) ; + } + } + for(j=0;j<64;j+=32){ + unsigned long long int t,b; + for(i=0;i<16;i++){ + t=halfrow[2*(j+i)]; + b=halfrow[2*(j+16+i)]; + halfrow[2*(j+i)] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); + halfrow[2*(j+16+i)]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; + t=halfrow[2*(j+i)+1]; + b=halfrow[2*(j+16+i)+1]; + halfrow[2*(j+i)+1] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); + halfrow[2*(j+16+i)+1]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; + } + } + for(j=0;j<64;j+=16){ + unsigned long long int t,b; + for(i=0;i<8;i++){ + t=halfrow[2*(j+i)]; + b=halfrow[2*(j+8+i)]; + halfrow[2*(j+i)] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); + halfrow[2*(j+8+i)] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); + t=halfrow[2*(j+i)+1]; + b=halfrow[2*(j+8+i)+1]; + halfrow[2*(j+i)+1] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); + halfrow[2*(j+8+i)+1] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); + } + } + for(j=0;j<64;j+=8){ + unsigned long long int t,b; + for(i=0;i<4;i++){ + t=halfrow[2*(j+i)]; + b=halfrow[2*(j+4+i)]; + halfrow[2*(j+i)] =((t&0x0f0f0f0f0f0f0f0fULL)<<4) | (b&0x0f0f0f0f0f0f0f0fULL); + halfrow[2*(j+4+i)] = (t&0xf0f0f0f0f0f0f0f0ULL) | ((b&0xf0f0f0f0f0f0f0f0ULL)>>4); + t=halfrow[2*(j+i)+1]; + b=halfrow[2*(j+4+i)+1]; + halfrow[2*(j+i)+1] =((t&0x0f0f0f0f0f0f0f0fULL)<<4) | (b&0x0f0f0f0f0f0f0f0fULL); + halfrow[2*(j+4+i)+1] = (t&0xf0f0f0f0f0f0f0f0ULL) | ((b&0xf0f0f0f0f0f0f0f0ULL)>>4); + } + } + for(j=0;j<64;j+=4){ + unsigned long long int t,b; + for(i=0;i<2;i++){ + t=halfrow[2*(j+i)]; + b=halfrow[2*(j+2+i)]; + halfrow[2*(j+i)] =((t&0x3333333333333333ULL)<<2) | (b&0x3333333333333333ULL); + halfrow[2*(j+2+i)] = (t&0xccccccccccccccccULL) | ((b&0xccccccccccccccccULL)>>2); + t=halfrow[2*(j+i)+1]; + b=halfrow[2*(j+2+i)+1]; + halfrow[2*(j+i)+1] =((t&0x3333333333333333ULL)<<2) | (b&0x3333333333333333ULL); + halfrow[2*(j+2+i)+1] = (t&0xccccccccccccccccULL) | ((b&0xccccccccccccccccULL)>>2); + } + } + for(j=0;j<64;j+=2){ + unsigned long long int t,b; + for(i=0;i<1;i++){ + t=halfrow[2*(j+i)]; + b=halfrow[2*(j+1+i)]; + halfrow[2*(j+i)] =((t&0x5555555555555555ULL)<<1) | (b&0x5555555555555555ULL); + halfrow[2*(j+1+i)] = (t&0xaaaaaaaaaaaaaaaaULL) | ((b&0xaaaaaaaaaaaaaaaaULL)>>1); + t=halfrow[2*(j+i)+1]; + b=halfrow[2*(j+1+i)+1]; + halfrow[2*(j+i)+1] =((t&0x5555555555555555ULL)<<1) | (b&0x5555555555555555ULL); + halfrow[2*(j+1+i)+1] = (t&0xaaaaaaaaaaaaaaaaULL) | ((b&0xaaaaaaaaaaaaaaaaULL)>>1); + } + } +#undef halfrow +} + +static inline void trasp64_128_88cw(unsigned char *data){ +/* 64 rows of 128 bits transposition (bytes transp. - 8x8 rotate clockwise)*/ +#define halfrow ((unsigned long long int *)data) + int i,j; + for(j=0;j<64;j+=64){ + unsigned long long int t,b; + for(i=0;i<32;i++){ + t=halfrow[2*(j+i)]; + b=halfrow[2*(j+32+i)]; + halfrow[2*(j+i)] = (t&0x00000000ffffffffULL) | ((b )<<32); + halfrow[2*(j+32+i)]=((t )>>32) | (b&0xffffffff00000000ULL) ; + t=halfrow[2*(j+i)+1]; + b=halfrow[2*(j+32+i)+1]; + halfrow[2*(j+i)+1] = (t&0x00000000ffffffffULL) | ((b )<<32); + halfrow[2*(j+32+i)+1]=((t )>>32) | (b&0xffffffff00000000ULL) ; + } + } + for(j=0;j<64;j+=32){ + unsigned long long int t,b; + for(i=0;i<16;i++){ + t=halfrow[2*(j+i)]; + b=halfrow[2*(j+16+i)]; + halfrow[2*(j+i)] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); + halfrow[2*(j+16+i)]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; + t=halfrow[2*(j+i)+1]; + b=halfrow[2*(j+16+i)+1]; + halfrow[2*(j+i)+1] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); + halfrow[2*(j+16+i)+1]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; + } + } + for(j=0;j<64;j+=16){ + unsigned long long int t,b; + for(i=0;i<8;i++){ + t=halfrow[2*(j+i)]; + b=halfrow[2*(j+8+i)]; + halfrow[2*(j+i)] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); + halfrow[2*(j+8+i)] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); + t=halfrow[2*(j+i)+1]; + b=halfrow[2*(j+8+i)+1]; + halfrow[2*(j+i)+1] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); + halfrow[2*(j+8+i)+1] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); + } + } + for(j=0;j<64;j+=8){ + unsigned long long int t,b; + for(i=0;i<4;i++){ + t=halfrow[2*(j+i)]; + b=halfrow[2*(j+4+i)]; + halfrow[2*(j+i)] =((t&0xf0f0f0f0f0f0f0f0ULL)>>4) | (b&0xf0f0f0f0f0f0f0f0ULL); + halfrow[2*(j+4+i)] = (t&0x0f0f0f0f0f0f0f0fULL) | ((b&0x0f0f0f0f0f0f0f0fULL)<<4); + t=halfrow[2*(j+i)+1]; + b=halfrow[2*(j+4+i)+1]; + halfrow[2*(j+i)+1] =((t&0xf0f0f0f0f0f0f0f0ULL)>>4) | (b&0xf0f0f0f0f0f0f0f0ULL); + halfrow[2*(j+4+i)+1] = (t&0x0f0f0f0f0f0f0f0fULL) | ((b&0x0f0f0f0f0f0f0f0fULL)<<4); + } + } + for(j=0;j<64;j+=4){ + unsigned long long int t,b; + for(i=0;i<2;i++){ + t=halfrow[2*(j+i)]; + b=halfrow[2*(j+2+i)]; + halfrow[2*(j+i)] =((t&0xccccccccccccccccULL)>>2) | (b&0xccccccccccccccccULL); + halfrow[2*(j+2+i)] = (t&0x3333333333333333ULL) | ((b&0x3333333333333333ULL)<<2); + t=halfrow[2*(j+i)+1]; + b=halfrow[2*(j+2+i)+1]; + halfrow[2*(j+i)+1] =((t&0xccccccccccccccccULL)>>2) | (b&0xccccccccccccccccULL); + halfrow[2*(j+2+i)+1] = (t&0x3333333333333333ULL) | ((b&0x3333333333333333ULL)<<2); + } + } + for(j=0;j<64;j+=2){ + unsigned long long int t,b; + for(i=0;i<1;i++){ + t=halfrow[2*(j+i)]; + b=halfrow[2*(j+1+i)]; + halfrow[2*(j+i)] =((t&0xaaaaaaaaaaaaaaaaULL)>>1) | (b&0xaaaaaaaaaaaaaaaaULL); + halfrow[2*(j+1+i)] = (t&0x5555555555555555ULL) | ((b&0x5555555555555555ULL)<<1); + t=halfrow[2*(j+i)+1]; + b=halfrow[2*(j+1+i)+1]; + halfrow[2*(j+i)+1] =((t&0xaaaaaaaaaaaaaaaaULL)>>1) | (b&0xaaaaaaaaaaaaaaaaULL); + halfrow[2*(j+1+i)+1] = (t&0x5555555555555555ULL) | ((b&0x5555555555555555ULL)<<1); + } + } +#undef halfrow +} +#endif + + +#ifdef STREAM_INIT +void stream_cypher_group_init( + struct stream_regs *regs, + group iA[8][4], // [In] iA00,iA01,...iA73 32 groups | Derived from key. + group iB[8][4], // [In] iB00,iB01,...iB73 32 groups | Derived from key. + unsigned char *sb) // [In] (SB0,SB1,...SB7)...x32 32*8 bytes | Extra input. +#endif +#ifdef STREAM_NORMAL +void stream_cypher_group_normal( + struct stream_regs *regs, + unsigned char *cb) // [Out] (CB0,CB1,...CB7)...x32 32*8 bytes | Output. +#endif +{ +#ifdef STREAM_INIT + group in1[4]; + group in2[4]; +#endif + group extra_B[4]; + group fa,fb,fc,fd,fe; + group s1a,s1b,s2a,s2b,s3a,s3b,s4a,s4b,s5a,s5b,s6a,s6b,s7a,s7b; + group next_E[4]; + group tmp0,tmp1,tmp2,tmp3,tmp4; +#ifdef STREAM_INIT + group *sb_g=(group *)sb; +#endif +#ifdef STREAM_NORMAL + group *cb_g=(group *)cb; +#endif + int aboff; + int i,j,k,b; + int dbg; + +#ifdef STREAM_INIT + DBG(fprintf(stderr,":::::::::: BEGIN STREAM INIT\n")); +#endif +#ifdef STREAM_NORMAL + DBG(fprintf(stderr,":::::::::: BEGIN STREAM NORMAL\n")); +#endif +#ifdef STREAM_INIT +for(j=0;j<64;j++){ + DBG(fprintf(stderr,"precall prerot stream_in[%2i]=",j)); + DBG(dump_mem("",sb+BYPG*j,BYPG,BYPG)); +} + +DBG(dump_mem("stream_prerot ",sb,GROUP_PARALLELISM*8,BYPG)); +#if GROUP_PARALLELISM==32 +trasp64_32_88ccw(sb); +#endif +#if GROUP_PARALLELISM==64 +trasp64_64_88ccw(sb); +#endif +#if GROUP_PARALLELISM==128 +trasp64_128_88ccw(sb); +#endif +DBG(dump_mem("stream_postrot",sb,GROUP_PARALLELISM*8,BYPG)); + +for(j=0;j<64;j++){ + DBG(fprintf(stderr,"precall stream_in[%2i]=",j)); + DBG(dump_mem("",sb+BYPG*j,BYPG,BYPG)); +} +#endif + + aboff=32; + +#ifdef STREAM_INIT + // load first 32 bits of ck into A[aboff+0]..A[aboff+7] + // load last 32 bits of ck into B[aboff+0]..B[aboff+7] + // all other regs = 0 + for(i=0;i<8;i++){ + for(b=0;b<4;b++){ +DBG(fprintf(stderr,"dbg from iA A[%i][%i]=",i,b)); +DBG(dump_mem("",(unsigned char *)&iA[i][b],BYPG,BYPG)); +DBG(fprintf(stderr," dbg from iB B[%i][%i]=",i,b)); +DBG(dump_mem("",(unsigned char *)&iB[i][b],BYPG,BYPG)); + regs->A[aboff+i][b]=iA[i][b]; + regs->B[aboff+i][b]=iB[i][b]; + } + } + for(b=0;b<4;b++){ + regs->A[aboff+8][b]=FF0(); + regs->A[aboff+9][b]=FF0(); + regs->B[aboff+8][b]=FF0(); + regs->B[aboff+9][b]=FF0(); + } + for(b=0;b<4;b++){ + regs->X[b]=FF0(); + regs->Y[b]=FF0(); + regs->Z[b]=FF0(); + regs->D[b]=FF0(); + regs->E[b]=FF0(); + regs->F[b]=FF0(); + } + regs->p=FF0(); + regs->q=FF0(); + regs->r=FF0(); +#endif + +for(dbg=0;dbg<4;dbg++){ + DBG(fprintf(stderr,"dbg A0[%i]=",dbg)); + DBG(dump_mem("",(unsigned char *)®s->A[aboff+0][dbg],BYPG,BYPG)); + DBG(fprintf(stderr,"dbg B0[%i]=",dbg)); + DBG(dump_mem("",(unsigned char *)®s->B[aboff+0][dbg],BYPG,BYPG)); +} + +//////////////////////////////////////////////////////////////////////////////// + + // EXTERNAL LOOP - 8 bytes per operation + for(i=0;i<8;i++){ + + DBG(fprintf(stderr,"--BEGIN EXTERNAL LOOP %i\n",i)); + +#ifdef STREAM_INIT + for(b=0;b<4;b++){ + in1[b]=sb_g[8*i+4+b]; + in2[b]=sb_g[8*i+b]; + } +#endif + + // INTERNAL LOOP - 2 bits per iteration + for(j=0; j<4; j++){ + + DBG(fprintf(stderr,"---BEGIN INTERNAL LOOP %i (EXT %i, INT %i)\n",j,i,j)); + + // from A0..A9, 35 bits are selected as inputs to 7 s-boxes + // 5 bits input per s-box, 2 bits output per s-box + + // we can select bits with zero masking and shifting operations + // and synthetize s-boxes with optimized boolean functions. + // this is the actual reason we do all the crazy transposition + // stuff to switch between normal and bit slice representations. + // this code really flies. + + fe=regs->A[aboff+3][0];fa=regs->A[aboff+0][2];fb=regs->A[aboff+5][1];fc=regs->A[aboff+6][3];fd=regs->A[aboff+8][0]; +/* 1000 1110 1110 0001 : lev 7: */ //tmp0=( fa^( fb^( ( ( ( fa|fb )^fc )|( fc^fd ) )^ALL_ONES ) ) ); +/* 1110 0010 0011 0011 : lev 6: */ //tmp1=( ( fa|fb )^( ( fc&( fa|( fb^fd ) ) )^ALL_ONES ) ); +/* 0011 0110 1000 1101 : lev 5: */ //tmp2=( fa^( ( fb&fd )^( ( fa&fd )|fc ) ) ); +/* 0101 0101 1001 0011 : lev 5: */ //tmp3=( ( fa&fc )^( fa^( ( fa&fb )|fd ) ) ); +/* 1000 1110 1110 0001 : lev 7: */ tmp0=FFXOR(fa,FFXOR(fb,FFXOR(FFOR(FFXOR(FFOR(fa,fb),fc),FFXOR(fc,fd)),FF1()))); +/* 1110 0010 0011 0011 : lev 6: */ tmp1=FFXOR(FFOR(fa,fb),FFXOR(FFAND(fc,FFOR(fa,FFXOR(fb,fd))),FF1())); +/* 0011 0110 1000 1101 : lev 5: */ tmp2=FFXOR(fa,FFXOR(FFAND(fb,fd),FFOR(FFAND(fa,fd),fc))); +/* 0101 0101 1001 0011 : lev 5: */ tmp3=FFXOR(FFAND(fa,fc),FFXOR(fa,FFOR(FFAND(fa,fb),fd))); + s1a=FFXOR(tmp0,FFAND(fe,tmp1)); + s1b=FFXOR(tmp2,FFAND(fe,tmp3)); +//dump_mem("s1as1b-fe",&fe,BYPG,BYPG); +//dump_mem("s1as1b-fa",&fa,BYPG,BYPG); +//dump_mem("s1as1b-fb",&fb,BYPG,BYPG); +//dump_mem("s1as1b-fc",&fc,BYPG,BYPG); +//dump_mem("s1as1b-fd",&fd,BYPG,BYPG); + + fe=regs->A[aboff+1][1];fa=regs->A[aboff+2][2];fb=regs->A[aboff+5][3];fc=regs->A[aboff+6][0];fd=regs->A[aboff+8][1]; +/* 1001 1110 0110 0001 : lev 6: */ //tmp0=( fa^( ( fb&( fc|fd ) )^( fc^( fd^ALL_ONES ) ) ) ); +/* 0000 0011 0111 1011 : lev 5: */ //tmp1=( ( fa&( fb^fd ) )|( ( fa|fb )&fc ) ); +/* 1100 0110 1101 0010 : lev 6: */ //tmp2=( ( fb&fd )^( ( fa&fd )|( fb^( fc^ALL_ONES ) ) ) ); +/* 0001 1110 1111 0101 : lev 5: */ //tmp3=( ( fa&fd )|( fa^( fb^( fc&fd ) ) ) ); +/* 1001 1110 0110 0001 : lev 6: */ tmp0=FFXOR(fa,FFXOR(FFAND(fb,FFOR(fc,fd)),FFXOR(fc,FFXOR(fd,FF1())))); +/* 0000 0011 0111 1011 : lev 5: */ tmp1=FFOR(FFAND(fa,FFXOR(fb,fd)),FFAND(FFOR(fa,fb),fc)); +/* 1100 0110 1101 0010 : lev 6: */ tmp2=FFXOR(FFAND(fb,fd),FFOR(FFAND(fa,fd),FFXOR(fb,FFXOR(fc,FF1())))); +/* 0001 1110 1111 0101 : lev 5: */ tmp3=FFOR(FFAND(fa,fd),FFXOR(fa,FFXOR(fb,FFAND(fc,fd)))); + s2a=FFXOR(tmp0,FFAND(fe,tmp1)); + s2b=FFXOR(tmp2,FFAND(fe,tmp3)); + + fe=regs->A[aboff+0][3];fa=regs->A[aboff+1][0];fb=regs->A[aboff+4][1];fc=regs->A[aboff+4][3];fd=regs->A[aboff+5][2]; +/* 0100 1011 1001 0110 : lev 5: */ //tmp0=( fa^( fb^( ( fc&( fa|fd ) )^fd ) ) ); +/* 1101 0101 1000 1100 : lev 7: */ //tmp1=( ( fa&fc )^( ( fa^fd )|( ( fb|fc )^( fd^ALL_ONES ) ) ) ); +/* 0010 0111 1101 1000 : lev 4: */ //tmp2=( fa^( ( ( fb^fc )&fd )^fc ) ); +/* 1111 1111 1111 1111 : lev 0: */ //tmp3=ALL_ONES; +/* 0100 1011 1001 0110 : lev 5: */ tmp0=FFXOR(fa,FFXOR(fb,FFXOR(FFAND(fc,FFOR(fa,fd)),fd))); +/* 1101 0101 1000 1100 : lev 7: */ tmp1=FFXOR(FFAND(fa,fc),FFOR(FFXOR(fa,fd),FFXOR(FFOR(fb,fc),FFXOR(fd,FF1())))); +/* 0010 0111 1101 1000 : lev 4: */ tmp2=FFXOR(fa,FFXOR(FFAND(FFXOR(fb,fc),fd),fc)); +/* 1111 1111 1111 1111 : lev 0: */ tmp3=FF1(); + s3a=FFXOR(tmp0,FFAND(FFNOT(fe),tmp1)); + s3b=FFXOR(tmp2,FFAND(fe,tmp3)); + + fe=regs->A[aboff+2][3];fa=regs->A[aboff+0][1];fb=regs->A[aboff+1][3];fc=regs->A[aboff+3][2];fd=regs->A[aboff+7][0]; +/* 1011 0101 0100 1001 : lev 7: */ //tmp0=( fa^( ( fc&( fa^fd ) )|( fb^( fc|( fd^ALL_ONES ) ) ) ) ); +/* 0010 1101 0110 0110 : lev 6: */ //tmp1=( ( fa&fb )^( fb^( ( ( fa|fc )&fd )^fc ) ) ); +/* 0110 0111 1101 0000 : lev 7: */ //tmp2=( fa^( ( fb&fc )|( ( ( fa&( fb^fd ) )|fc )^fd ) ) ); +/* 1111 1111 1111 1111 : lev 0: */ //tmp3=ALL_ONES; +/* 1011 0101 0100 1001 : lev 7: */ tmp0=FFXOR(fa,FFOR(FFAND(fc,FFXOR(fa,fd)),FFXOR(fb,FFOR(fc,FFXOR(fd,FF1()))))); +/* 0010 1101 0110 0110 : lev 6: */ tmp1=FFXOR(FFAND(fa,fb),FFXOR(fb,FFXOR(FFAND(FFOR(fa,fc),fd),fc))); +/* 0110 0111 1101 0000 : lev 7: */ tmp2=FFXOR(fa,FFOR(FFAND(fb,fc),FFXOR(FFOR(FFAND(fa,FFXOR(fb,fd)),fc),fd))); +/* 1111 1111 1111 1111 : lev 0: */ tmp3=FF1(); + s4a=FFXOR(tmp0,FFAND(fe,FFXOR(tmp1,tmp0))); + s4b=FFXOR(FFXOR(s4a,tmp2),FFAND(fe,tmp3)); + + fe=regs->A[aboff+4][2];fa=regs->A[aboff+3][3];fb=regs->A[aboff+5][0];fc=regs->A[aboff+7][1];fd=regs->A[aboff+8][2]; +/* 1000 1111 0011 0010 : lev 7: */ //tmp0=( ( ( fa&( fb|fc ) )^fb )|( ( ( fa^fc )|fd )^ALL_ONES ) ); +/* 0110 1011 0000 1011 : lev 6: */ //tmp1=( fb^( ( fc^fd )&( fc^( fb|( fa^fd ) ) ) ) ); +/* 0001 1010 0111 1001 : lev 6: */ //tmp2=( ( fa&fc )^( fb^( ( fb|( fa^fc ) )&fd ) ) ); +/* 0101 1101 1101 0101 : lev 4: */ //tmp3=( ( ( fa^fb )&( fc^ALL_ONES ) )|fd ); +/* 1000 1111 0011 0010 : lev 7: */ tmp0=FFOR(FFXOR(FFAND(fa,FFOR(fb,fc)),fb),FFXOR(FFOR(FFXOR(fa,fc),fd),FF1())); +/* 0110 1011 0000 1011 : lev 6: */ tmp1=FFXOR(fb,FFAND(FFXOR(fc,fd),FFXOR(fc,FFOR(fb,FFXOR(fa,fd))))); +/* 0001 1010 0111 1001 : lev 6: */ tmp2=FFXOR(FFAND(fa,fc),FFXOR(fb,FFAND(FFOR(fb,FFXOR(fa,fc)),fd))); +/* 0101 1101 1101 0101 : lev 4: */ tmp3=FFOR(FFAND(FFXOR(fa,fb),FFXOR(fc,FF1())),fd); + s5a=FFXOR(tmp0,FFAND(fe,tmp1)); + s5b=FFXOR(tmp2,FFAND(fe,tmp3)); + + fe=regs->A[aboff+2][1];fa=regs->A[aboff+3][1];fb=regs->A[aboff+4][0];fc=regs->A[aboff+6][2];fd=regs->A[aboff+8][3]; +/* 0011 0110 0010 1101 : lev 6: */ //tmp0=( ( ( fa&fc )&fd )^( ( fb&( fa|fd ) )^fc ) ); +/* 1110 1110 1011 1011 : lev 3: */ //tmp1=( ( ( fa^fc )&fd )^ALL_ONES ); +/* 0101 1000 0110 0111 : lev 6: */ //tmp2=( ( fa&( fb|fc ) )^( fb^( ( fb&fc )|fd ) ) ); +/* 0001 0011 0000 0001 : lev 5: */ //tmp3=( fc&( ( fa&( fb^fd ) )^( fb|fd ) ) ); +/* 0011 0110 0010 1101 : lev 6: */ tmp0=FFXOR(FFAND(FFAND(fa,fc),fd),FFXOR(FFAND(fb,FFOR(fa,fd)),fc)); +/* 1110 1110 1011 1011 : lev 3: */ tmp1=FFXOR(FFAND(FFXOR(fa,fc),fd),FF1()); +/* 0101 1000 0110 0111 : lev 6: */ tmp2=FFXOR(FFAND(fa,FFOR(fb,fc)),FFXOR(fb,FFOR(FFAND(fb,fc),fd))); +/* 0001 0011 0000 0001 : lev 5: */ tmp3=FFAND(fc,FFXOR(FFAND(fa,FFXOR(fb,fd)),FFOR(fb,fd))); + s6a=FFXOR(tmp0,FFAND(fe,tmp1)); + s6b=FFXOR(tmp2,FFAND(fe,tmp3)); + + fe=regs->A[aboff+1][2];fa=regs->A[aboff+2][0];fb=regs->A[aboff+6][1];fc=regs->A[aboff+7][2];fd=regs->A[aboff+7][3]; +/* 0111 1000 1001 0110 : lev 5: */ //tmp0=( fb^( ( fc&fd )|( fa^( fc^fd ) ) ) ); +/* 0100 1001 0101 1011 : lev 6: */ //tmp1=( ( fb|fd )&( ( fa&fc )|( fb^( fc^fd ) ) ) ); +/* 0100 1001 1011 1001 : lev 5: */ //tmp2=( ( fa|fb )^( ( fc&( fb|fd ) )^fd ) ); +/* 1111 1111 1101 1101 : lev 3: */ //tmp3=( fd|( ( fa&fc )^ALL_ONES ) ); +/* 0111 1000 1001 0110 : lev 5: */ tmp0=FFXOR(fb,FFOR(FFAND(fc,fd),FFXOR(fa,FFXOR(fc,fd)))); +/* 0100 1001 0101 1011 : lev 6: */ tmp1=FFAND(FFOR(fb,fd),FFOR(FFAND(fa,fc),FFXOR(fb,FFXOR(fc,fd)))); +/* 0100 1001 1011 1001 : lev 5: */ tmp2=FFXOR(FFOR(fa,fb),FFXOR(FFAND(fc,FFOR(fb,fd)),fd)); +/* 1111 1111 1101 1101 : lev 3: */ tmp3=FFOR(fd,FFXOR(FFAND(fa,fc),FF1())); + s7a=FFXOR(tmp0,FFAND(fe,tmp1)); + s7b=FFXOR(tmp2,FFAND(fe,tmp3)); + + +/* + we have just done this: + + int sbox1[0x20] = {2,0,1,1,2,3,3,0, 3,2,2,0,1,1,0,3, 0,3,3,0,2,2,1,1, 2,2,0,3,1,1,3,0}; + int sbox2[0x20] = {3,1,0,2,2,3,3,0, 1,3,2,1,0,0,1,2, 3,1,0,3,3,2,0,2, 0,0,1,2,2,1,3,1}; + int sbox3[0x20] = {2,0,1,2,2,3,3,1, 1,1,0,3,3,0,2,0, 1,3,0,1,3,0,2,2, 2,0,1,2,0,3,3,1}; + int sbox4[0x20] = {3,1,2,3,0,2,1,2, 1,2,0,1,3,0,0,3, 1,0,3,1,2,3,0,3, 0,3,2,0,1,2,2,1}; + int sbox5[0x20] = {2,0,0,1,3,2,3,2, 0,1,3,3,1,0,2,1, 2,3,2,0,0,3,1,1, 1,0,3,2,3,1,0,2}; + int sbox6[0x20] = {0,1,2,3,1,2,2,0, 0,1,3,0,2,3,1,3, 2,3,0,2,3,0,1,1, 2,1,1,2,0,3,3,0}; + int sbox7[0x20] = {0,3,2,2,3,0,0,1, 3,0,1,3,1,2,2,1, 1,0,3,3,0,1,1,2, 2,3,1,0,2,3,0,2}; + + s12 = sbox1[ (((A3>>0)&1)<<4) | (((A0>>2)&1)<<3) | (((A5>>1)&1)<<2) | (((A6>>3)&1)<<1) | (((A8>>0)&1)<<0) ] + |sbox2[ (((A1>>1)&1)<<4) | (((A2>>2)&1)<<3) | (((A5>>3)&1)<<2) | (((A6>>0)&1)<<1) | (((A8>>1)&1)<<0) ]; + s34 = sbox3[ (((A0>>3)&1)<<4) | (((A1>>0)&1)<<3) | (((A4>>1)&1)<<2) | (((A4>>3)&1)<<1) | (((A5>>2)&1)<<0) ] + |sbox4[ (((A2>>3)&1)<<4) | (((A0>>1)&1)<<3) | (((A1>>3)&1)<<2) | (((A3>>2)&1)<<1) | (((A7>>0)&1)<<0) ]; + s56 = sbox5[ (((A4>>2)&1)<<4) | (((A3>>3)&1)<<3) | (((A5>>0)&1)<<2) | (((A7>>1)&1)<<1) | (((A8>>2)&1)<<0) ] + |sbox6[ (((A2>>1)&1)<<4) | (((A3>>1)&1)<<3) | (((A4>>0)&1)<<2) | (((A6>>2)&1)<<1) | (((A8>>3)&1)<<0) ]; + s7 = sbox7[ (((A1>>2)&1)<<4) | (((A2>>0)&1)<<3) | (((A6>>1)&1)<<2) | (((A7>>2)&1)<<1) | (((A7>>3)&1)<<0) ]; +*/ + + // use 4x4 xor to produce extra nibble for T3 + + extra_B[3]=FFXOR(FFXOR(FFXOR(regs->B[aboff+2][0],regs->B[aboff+5][1]),regs->B[aboff+6][2]),regs->B[aboff+8][3]); + extra_B[2]=FFXOR(FFXOR(FFXOR(regs->B[aboff+5][0],regs->B[aboff+7][1]),regs->B[aboff+2][3]),regs->B[aboff+3][2]); + extra_B[1]=FFXOR(FFXOR(FFXOR(regs->B[aboff+4][3],regs->B[aboff+7][2]),regs->B[aboff+3][0]),regs->B[aboff+4][1]); + extra_B[0]=FFXOR(FFXOR(FFXOR(regs->B[aboff+8][2],regs->B[aboff+5][3]),regs->B[aboff+2][1]),regs->B[aboff+7][0]); +for(dbg=0;dbg<4;dbg++){ + DBG(fprintf(stderr,"extra_B[%i]=",dbg)); + DBG(dump_mem("",(unsigned char *)&extra_B[dbg],BYPG,BYPG)); +} + + // T1 = xor all inputs + // in1, in2, D are only used in T1 during initialisation, not generation + for(b=0;b<4;b++){ + regs->A[aboff-1][b]=FFXOR(regs->A[aboff+9][b],regs->X[b]); + } + +#ifdef STREAM_INIT + for(b=0;b<4;b++){ + regs->A[aboff-1][b]=FFXOR(FFXOR(regs->A[aboff-1][b],regs->D[b]),((j % 2) ? in2[b] : in1[b])); + } +#endif + +for(dbg=0;dbg<4;dbg++){ + DBG(fprintf(stderr,"next_A0[%i]=",dbg)); + DBG(dump_mem("",(unsigned char *)®s->A[aboff-1][dbg],BYPG,BYPG)); +} + + // T2 = xor all inputs + // in1, in2 are only used in T1 during initialisation, not generation + // if p=0, use this, if p=1, rotate the result left + for(b=0;b<4;b++){ + regs->B[aboff-1][b]=FFXOR(FFXOR(regs->B[aboff+6][b],regs->B[aboff+9][b]),regs->Y[b]); + } + +#ifdef STREAM_INIT + for(b=0;b<4;b++){ + regs->B[aboff-1][b]=FFXOR(regs->B[aboff-1][b],((j % 2) ? in1[b] : in2[b])); + } +#endif + +for(dbg=0;dbg<4;dbg++){ + DBG(fprintf(stderr,"next_B0[%i]=",dbg)); + DBG(dump_mem("",(unsigned char *)®s->B[aboff-1][dbg],BYPG,BYPG)); +} + + // if p=1, rotate left (yes, this is what we're doing) + tmp3=regs->B[aboff-1][3]; + regs->B[aboff-1][3]=FFXOR(regs->B[aboff-1][3],FFAND(FFXOR(regs->B[aboff-1][3],regs->B[aboff-1][2]),regs->p)); + regs->B[aboff-1][2]=FFXOR(regs->B[aboff-1][2],FFAND(FFXOR(regs->B[aboff-1][2],regs->B[aboff-1][1]),regs->p)); + regs->B[aboff-1][1]=FFXOR(regs->B[aboff-1][1],FFAND(FFXOR(regs->B[aboff-1][1],regs->B[aboff-1][0]),regs->p)); + regs->B[aboff-1][0]=FFXOR(regs->B[aboff-1][0],FFAND(FFXOR(regs->B[aboff-1][0],tmp3),regs->p)); + +for(dbg=0;dbg<4;dbg++){ + DBG(fprintf(stderr,"next_B0[%i]=",dbg)); + DBG(dump_mem("",(unsigned char *)®s->B[aboff-1][dbg],BYPG,BYPG)); +} + + // T3 = xor all inputs + for(b=0;b<4;b++){ + regs->D[b]=FFXOR(FFXOR(regs->E[b],regs->Z[b]),extra_B[b]); + } + +for(dbg=0;dbg<4;dbg++){ + DBG(fprintf(stderr,"D[%i]=",dbg)); + DBG(dump_mem("",(unsigned char *)®s->D[dbg],BYPG,BYPG)); +} + + // T4 = sum, carry of Z + E + r + for(b=0;b<4;b++){ + next_E[b]=regs->F[b]; + } + + tmp0=FFXOR(regs->Z[0],regs->E[0]); + tmp1=FFAND(regs->Z[0],regs->E[0]); + regs->F[0]=FFXOR(regs->E[0],FFAND(regs->q,FFXOR(regs->Z[0],regs->r))); + tmp3=FFAND(tmp0,regs->r); + tmp4=FFOR(tmp1,tmp3); + + tmp0=FFXOR(regs->Z[1],regs->E[1]); + tmp1=FFAND(regs->Z[1],regs->E[1]); + regs->F[1]=FFXOR(regs->E[1],FFAND(regs->q,FFXOR(regs->Z[1],tmp4))); + tmp3=FFAND(tmp0,tmp4); + tmp4=FFOR(tmp1,tmp3); + + tmp0=FFXOR(regs->Z[2],regs->E[2]); + tmp1=FFAND(regs->Z[2],regs->E[2]); + regs->F[2]=FFXOR(regs->E[2],FFAND(regs->q,FFXOR(regs->Z[2],tmp4))); + tmp3=FFAND(tmp0,tmp4); + tmp4=FFOR(tmp1,tmp3); + + tmp0=FFXOR(regs->Z[3],regs->E[3]); + tmp1=FFAND(regs->Z[3],regs->E[3]); + regs->F[3]=FFXOR(regs->E[3],FFAND(regs->q,FFXOR(regs->Z[3],tmp4))); + tmp3=FFAND(tmp0,tmp4); + regs->r=FFXOR(regs->r,FFAND(regs->q,FFXOR(FFOR(tmp1,tmp3),regs->r))); // ultimate carry + +/* + we have just done this: (believe it or not) + + if (q) { + F = Z + E + r; + r = (F >> 4) & 1; + F = F & 0x0f; + } + else { + F = E; + } +*/ + for(b=0;b<4;b++){ + regs->E[b]=next_E[b]; + } +for(dbg=0;dbg<4;dbg++){ + DBG(fprintf(stderr,"F[%i]=",dbg)); + DBG(dump_mem("",(unsigned char *)®s->F[dbg],BYPG,BYPG)); +} +DBG(fprintf(stderr,"r=")); +DBG(dump_mem("",(unsigned char *)®s->r,BYPG,BYPG)); +for(dbg=0;dbg<4;dbg++){ + DBG(fprintf(stderr,"E[%i]=",dbg)); + DBG(dump_mem("",(unsigned char *)®s->E[dbg],BYPG,BYPG)); +} + + // this simple instruction is virtually shifting all the shift registers + aboff--; + +/* + we've just done this: + + A9=A8;A8=A7;A7=A6;A6=A5;A5=A4;A4=A3;A3=A2;A2=A1;A1=A0;A0=next_A0; + B9=B8;B8=B7;B7=B6;B6=B5;B5=B4;B4=B3;B3=B2;B2=B1;B1=B0;B0=next_B0; +*/ + + regs->X[0]=s1a; + regs->X[1]=s2a; + regs->X[2]=s3b; + regs->X[3]=s4b; + regs->Y[0]=s3a; + regs->Y[1]=s4a; + regs->Y[2]=s5b; + regs->Y[3]=s6b; + regs->Z[0]=s5a; + regs->Z[1]=s6a; + regs->Z[2]=s1b; + regs->Z[3]=s2b; + regs->p=s7a; + regs->q=s7b; +for(dbg=0;dbg<4;dbg++){ + DBG(fprintf(stderr,"X[%i]=",dbg)); + DBG(dump_mem("",(unsigned char *)®s->X[dbg],BYPG,BYPG)); +} +for(dbg=0;dbg<4;dbg++){ + DBG(fprintf(stderr,"Y[%i]=",dbg)); + DBG(dump_mem("",(unsigned char *)®s->Y[dbg],BYPG,BYPG)); +} +for(dbg=0;dbg<4;dbg++){ + DBG(fprintf(stderr,"Z[%i]=",dbg)); + DBG(dump_mem("",(unsigned char *)®s->Z[dbg],BYPG,BYPG)); +} +DBG(fprintf(stderr,"p=")); +DBG(dump_mem("",(unsigned char *)®s->p,BYPG,BYPG)); +DBG(fprintf(stderr,"q=")); +DBG(dump_mem("",(unsigned char *)®s->q,BYPG,BYPG)); + +#ifdef STREAM_NORMAL + // require 4 loops per output byte + // 2 output bits are a function of the 4 bits of D + // xor 2 by 2 + cb_g[8*i+7-2*j]=FFXOR(regs->D[2],regs->D[3]); + cb_g[8*i+6-2*j]=FFXOR(regs->D[0],regs->D[1]); +for(dbg=0;dbg<8;dbg++){ + DBG(fprintf(stderr,"op[%i]=",dbg)); + DBG(dump_mem("",(unsigned char *)&cb_g[8*i+dbg],BYPG,BYPG)); +} +#endif + +DBG(fprintf(stderr,"---END INTERNAL LOOP\n")); + + } // INTERNAL LOOP + +DBG(fprintf(stderr,"--END EXTERNAL LOOP\n")); + + } // EXTERNAL LOOP + + // move 32 steps forward, ready for next call + for(k=0;k<10;k++){ + for(b=0;b<4;b++){ +DBG(fprintf(stderr,"moving forward AB k=%i b=%i\n",k,b)); + regs->A[32+k][b]=regs->A[k][b]; + regs->B[32+k][b]=regs->B[k][b]; + } + } + + +//////////////////////////////////////////////////////////////////////////////// + +#ifdef STREAM_NORMAL +for(j=0;j<64;j++){ + DBG(fprintf(stderr,"postcall prerot cb[%2i]=",j)); + DBG(dump_mem("",(unsigned char *)(cb+BYPG*j),BYPG,BYPG)); +} + +#if GROUP_PARALLELISM==32 +trasp64_32_88cw(cb); +#endif +#if GROUP_PARALLELISM==64 +trasp64_64_88cw(cb); +#endif +#if GROUP_PARALLELISM==128 +trasp64_128_88cw(cb); +#endif + +for(j=0;j<64;j++){ + DBG(fprintf(stderr,"postcall postrot cb[%2i]=",j)); + DBG(dump_mem("",(unsigned char *)(cb+BYPG*j),BYPG,BYPG)); +} +#endif + +#ifdef STREAM_INIT + DBG(fprintf(stderr,":::::::::: END STREAM INIT\n")); +#endif +#ifdef STREAM_NORMAL + DBG(fprintf(stderr,":::::::::: END STREAM NORMAL\n")); +#endif + +} + diff --git a/krypt.c b/krypt.c new file mode 100644 index 00000000..964826eb --- /dev/null +++ b/krypt.c @@ -0,0 +1,8 @@ +#define _XOPEN_SOURCE +#include + +char * +cwc_krypt(const char *key, const char *salt) +{ + return crypt(key, salt); +} diff --git a/main.c b/main.c index a7c52fbf..5ad59f04 100644 --- a/main.c +++ b/main.c @@ -55,7 +55,7 @@ #include "htmlui.h" #include "avgen.h" #include "file_input.h" -#include "plugin.h" +#include "cwc.h" int running; int xmltvreload; @@ -200,7 +200,7 @@ main(int argc, char **argv) file_input_init(); - plugin_init(); + cwc_init(); running = 1; while(running) { @@ -212,6 +212,9 @@ main(int argc, char **argv) syslog(LOG_NOTICE, "Initial input setup completed, starting output modules"); + fprintf(stderr, + "Initial input setup completed, starting output modules\n"); + pvr_init(); output_multicast_setup(); client_start(); diff --git a/transports.c b/transports.c index fbb7823c..7058f1ed 100644 --- a/transports.c +++ b/transports.c @@ -52,8 +52,8 @@ #include "psi.h" #include "pes.h" #include "buffer.h" -#include "plugin.h" #include "channels.h" +#include "cwc.h" static dtimer_t transport_monitor_timer; @@ -63,9 +63,9 @@ void transport_stop(th_transport_t *t, int flush_subscriptions) { th_subscription_t *s; + th_descrambler_t *td; th_stream_t *st; th_pkt_t *pkt; - th_plugin_t *p; if(flush_subscriptions) { while((s = LIST_FIRST(&t->tht_subscriptions)) != NULL) @@ -75,12 +75,11 @@ transport_stop(th_transport_t *t, int flush_subscriptions) return; } - LIST_FOREACH(p, &th_plugins, thp_link) - if(p->thp_transport_stop != NULL) - p->thp_transport_stop(p, &t->tht_plugin_aux, t); - t->tht_stop_feed(t); + while((td = LIST_FIRST(&t->tht_descramblers)) != NULL) + td->td_stop(td); + t->tht_tt_commercial_advice = COMMERCIAL_UNKNOWN; @@ -151,7 +150,6 @@ transport_start(th_transport_t *t, unsigned int weight) th_stream_t *st; AVCodec *c; enum CodecID id; - th_plugin_t *p; assert(t->tht_status != TRANSPORT_RUNNING); @@ -190,11 +188,7 @@ transport_start(th_transport_t *t, unsigned int weight) } } - LIST_FOREACH(p, &th_plugins, thp_link) - if(p->thp_transport_start != NULL) - p->thp_transport_start(p, &t->tht_plugin_aux, t); - - + cwc_transport_start(t); return 0; } diff --git a/tsdemux.c b/tsdemux.c index 8eb181bf..67ba42bc 100644 --- a/tsdemux.c +++ b/tsdemux.c @@ -113,11 +113,11 @@ ts_reassembly(th_transport_t *t, th_stream_t *st, uint8_t *data, int len, static void got_section(th_transport_t *t, th_stream_t *st) { - th_plugin_t *p; - LIST_FOREACH(p, &th_plugins, thp_link) - if(p->thp_psi_table != NULL) - p->thp_psi_table(p, &t->tht_plugin_aux, t, st, - st->st_section->ps_data, st->st_section->ps_offset); + th_descrambler_t *td; + + LIST_FOREACH(td, &t->tht_descramblers, td_transport_link) + td->td_table(td, t, st, + st->st_section->ps_data, st->st_section->ps_offset); if(st->st_got_section != NULL) st->st_got_section(t, st, st->st_section->ps_data, @@ -130,14 +130,13 @@ got_section(th_transport_t *t, th_stream_t *st) * Process transport stream packets */ void -ts_recv_packet(th_transport_t *t, int pid, uint8_t *tsb, int doplugin) +ts_recv_packet(th_transport_t *t, int pid, uint8_t *tsb, int dodescramble) { th_stream_t *st = NULL; th_subscription_t *s; int cc, err = 0, afc, afl = 0; int len, pusi; - pluginaux_t *pa; - th_plugin_t *p; + th_descrambler_t *td; LIST_FOREACH(st, &t->tht_streams, st_link) if(st->st_pid == pid) @@ -146,14 +145,10 @@ ts_recv_packet(th_transport_t *t, int pid, uint8_t *tsb, int doplugin) if(st == NULL) return; - if(doplugin) { - LIST_FOREACH(pa, &t->tht_plugin_aux, pa_link) { - p = pa->pa_plugin; - if(p->thp_tsb_process != NULL) - if(p->thp_tsb_process(pa, t, st, tsb)) - return; - } - } + if(((tsb[3] >> 6) & 3) && dodescramble) + LIST_FOREACH(td, &t->tht_descramblers, td_transport_link) + if(td->td_descramble(td, t, st, tsb)) + return; avgstat_add(&t->tht_rate, 188, dispatch_clock); if((tsb[3] >> 6) & 3) diff --git a/tvhead.h b/tvhead.h index 8d826bae..e8f5792d 100644 --- a/tvhead.h +++ b/tvhead.h @@ -85,6 +85,7 @@ TAILQ_HEAD(th_pkt_queue, th_pkt); LIST_HEAD(th_pkt_list, th_pkt); LIST_HEAD(th_muxer_list, th_muxer); LIST_HEAD(th_muxstream_list, th_muxstream); +LIST_HEAD(th_descrambler_list, th_descrambler); extern time_t dispatch_clock; @@ -236,7 +237,23 @@ typedef struct th_dvb_adapter { } th_dvb_adapter_t; +/** + * Descrambler superclass + * + * Created/Destroyed on per-transport basis upon transport start/stop + */ +typedef struct th_descrambler { + LIST_ENTRY(th_descrambler) td_transport_link; + void (*td_table)(struct th_descrambler *d, struct th_transport *t, + struct th_stream *st, uint8_t *section, int section_len); + + int (*td_descramble)(struct th_descrambler *d, struct th_transport *t, + struct th_stream *st, uint8_t *tsb); + + void (*td_stop)(struct th_descrambler *d); + +} th_descrambler_t; @@ -421,12 +438,8 @@ typedef struct th_transport { struct { struct file_input *file_input; } file_input; - - char pad[256]; /* for api stability */ - } u; - int tht_scrambled; /* informational */ const char *tht_provider; const char *tht_uniquename; const char *tht_network; @@ -436,6 +449,14 @@ typedef struct th_transport { THT_OTHER, } tht_source_type; + /* + * (De)scrambling support + */ + + struct th_descrambler_list tht_descramblers; + int tht_scrambled; + int tht_caid; + } th_transport_t;