/* This file is part of libdvbcsa. libdvbcsa 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. libdvbcsa 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 libdvbcsa; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Based on FFdecsa, Copyright (C) 2003-2004 fatih89r (c) 2006-2008 Alexandre Becoulet */ #include "dvbcsa/dvbcsa.h" #include "dvbcsa_bs.h" #define BS_XOREQ(a, b) do { dvbcsa_bs_word_t *_t = &(a); *_t = BS_XOR(*_t, (b)); } while (0) DVBCSA_INLINE static inline void dvbcsa_bs_block_decrypt_register (const dvbcsa_bs_word_t *block, dvbcsa_bs_word_t *r) { int i, j, g; r += 8 * 56; // loop over kk[55]..kk[0] for (i = 55; i >= 0; i--) { dvbcsa_bs_word_t *r6_N = r + 8 * 6; r -= 8; /* virtual shift of registers */ for (g = 0; g < 8; g++) { union { dvbcsa_bs_word_t so; uint8_t si[BS_BATCH_BYTES]; } u; u.so = BS_XOR(block[i], r6_N[g]); for (j = 0; j < BS_BATCH_BYTES; j++) u.si[j] = dvbcsa_block_sbox[u.si[j]]; dvbcsa_bs_word_t sbox_out = u.so; // bit permutation dvbcsa_bs_word_t in = BS_OR( BS_OR( BS_OR (BS_SHL (BS_AND (sbox_out, BS_VAL8(29)), 1), BS_SHL (BS_AND (sbox_out, BS_VAL8(02)), 6)), BS_OR (BS_SHL (BS_AND (sbox_out, BS_VAL8(04)), 3), BS_SHR (BS_AND (sbox_out, BS_VAL8(10)), 2))), BS_OR( BS_SHR (BS_AND (sbox_out, BS_VAL8(40)), 6), BS_SHR (BS_AND (sbox_out, BS_VAL8(80)), 4))); dvbcsa_bs_word_t w = BS_XOR(r[8 * 8 + g], sbox_out); r[8 * 0 + g] = w; BS_XOREQ(r[8 * 2 + g], w); BS_XOREQ(r[8 * 3 + g], w); BS_XOREQ(r[8 * 4 + g], w); BS_XOREQ(r[8 * 6 + g], in); } } } DVBCSA_INLINE static inline void dvbcsa_bs_block_decrypt_block(const struct dvbcsa_bs_key_s *key, const struct dvbcsa_bs_batch_s *pcks, unsigned int offset) { dvbcsa_bs_word_t r[8 * (8 + 56)]; dvbcsa_bs_block_transpose_in(r + 8 * 56, pcks, offset); dvbcsa_bs_block_decrypt_register(key->block, r); dvbcsa_bs_block_transpose_out(r, pcks, offset); } void dvbcsa_bs_block_decrypt_batch(const struct dvbcsa_bs_key_s *key, const struct dvbcsa_bs_batch_s *pcks, unsigned int maxlen) { unsigned int i; /* decrypt first block */ dvbcsa_bs_block_decrypt_block(key, pcks, 0); for (i = 8; i < maxlen; i += 8) { unsigned int g; /* chained cipher XOR */ for (g = 0; pcks[g].data; g++) if (i < (pcks[g].len & (unsigned)~0x7)) dvbcsa_xor_64(pcks[g].data + i - 8, pcks[g].data + i); /* decrypt other blocks */ dvbcsa_bs_block_decrypt_block(key, pcks, i); } } DVBCSA_INLINE static inline void dvbcsa_bs_block_encrypt_register (const dvbcsa_bs_word_t *block, dvbcsa_bs_word_t *r) { int i, j, g; // loop over kk[55]..kk[0] for (i = 0; i < 56; i++) { dvbcsa_bs_word_t *r7_N = r + 8 * 7; r += 8; /* virtual shift of registers */ for (g = 0; g < 8; g++) { union { dvbcsa_bs_word_t so; uint8_t si[BS_BATCH_BYTES]; } u; u.so = BS_XOR(block[i], r7_N[g]); for (j = 0; j < BS_BATCH_BYTES; j++) u.si[j] = dvbcsa_block_sbox[u.si[j]]; dvbcsa_bs_word_t sbox_out = u.so; // bit permutation dvbcsa_bs_word_t in = BS_OR( BS_OR( BS_OR (BS_SHL (BS_AND (sbox_out, BS_VAL8(29)), 1), BS_SHL (BS_AND (sbox_out, BS_VAL8(02)), 6)), BS_OR (BS_SHL (BS_AND (sbox_out, BS_VAL8(04)), 3), BS_SHR (BS_AND (sbox_out, BS_VAL8(10)), 2))), BS_OR( BS_SHR (BS_AND (sbox_out, BS_VAL8(40)), 6), BS_SHR (BS_AND (sbox_out, BS_VAL8(80)), 4))); dvbcsa_bs_word_t w = r[-8 * 1 + g]; r[8 * 7 + g] = BS_XOR(w, sbox_out); BS_XOREQ(r[8 * 1 + g], w); BS_XOREQ(r[8 * 2 + g], w); BS_XOREQ(r[8 * 3 + g], w); BS_XOREQ(r[8 * 5 + g], in); } } } DVBCSA_INLINE static inline void dvbcsa_bs_block_encrypt_block(const struct dvbcsa_bs_key_s *key, const struct dvbcsa_bs_batch_s *pcks, unsigned int offset) { dvbcsa_bs_word_t r[8 * (8 + 56)]; dvbcsa_bs_block_transpose_in(r, pcks, offset); dvbcsa_bs_block_encrypt_register(key->block, r); dvbcsa_bs_block_transpose_out(r + 8 * 56, pcks, offset); } void dvbcsa_bs_block_encrypt_batch(const struct dvbcsa_bs_key_s *key, const struct dvbcsa_bs_batch_s *pcks, unsigned int maxlen) { int i; dvbcsa_bs_block_encrypt_block(key, pcks, maxlen - 8); for (i = maxlen - 16; i >= 0; i -= 8) { unsigned int g; /* chained cipher XOR */ for (g = 0; pcks[g].data; g++) if (i + 8 < (pcks[g].len & (unsigned)~0x7)) dvbcsa_xor_64(pcks[g].data + i, pcks[g].data + i + 8); /* encrypt other blocks */ dvbcsa_bs_block_encrypt_block(key, pcks, i); } }