📄 mpeg3css.c
字号:
/* * We use two LFSR's (seeded from some of the input data bytes) to * generate two streams of pseudo-random bits. These two bit streams * are then combined by simply adding with carry to generate a final * sequence of pseudo-random bits which is stored in the buffer that * 'output' points to the end of - len is the size of this buffer. * * The first LFSR is of degree 25, and has a polynomial of: * x^13 + x^5 + x^4 + x^1 + 1 * * The second LSFR is of degree 17, and has a (primitive) polynomial of: * x^15 + x^1 + 1 * * I don't know if these polynomials are primitive modulo 2, and thus * represent maximal-period LFSR's. * * * Note that we take the output of each LFSR from the new shifted in * bit, not the old shifted out bit. Thus for ease of use the LFSR's * are implemented in bit reversed order. * */#define BIT0(x) ((x) & 1)#define BIT1(x) (((x) >> 1) & 1)static void generate_bits(unsigned char *output, int len, struct mpeg3_block const *s){ unsigned long lfsr0, lfsr1; unsigned char carry; /* In order to ensure that the LFSR works we need to ensure that the * initial values are non-zero. Thus when we initialise them from * the seed, we ensure that a bit is set. */ lfsr0 = (s->b[0] << 17) | (s->b[1] << 9) | ((s->b[2] & ~7) << 1) | 8 | (s->b[2] & 7); lfsr1 = (s->b[3] << 9) | 0x100 | s->b[4]; ++output; carry = 0; do{ int bit; unsigned char val; for (bit = 0, val = 0; bit < 8; ++bit) { unsigned char o_lfsr0, o_lfsr1; /* Actually only 1 bit each */ unsigned char combined; o_lfsr0 = ((lfsr0 >> 24) ^ (lfsr0 >> 21) ^ (lfsr0 >> 20) ^ (lfsr0 >> 12)) & 1; lfsr0 = (lfsr0 << 1) | o_lfsr0; o_lfsr1 = ((lfsr1 >> 16) ^ (lfsr1 >> 2)) & 1; lfsr1 = (lfsr1 << 1) | o_lfsr1; combined = !o_lfsr1 + carry + !o_lfsr0; carry = BIT1(combined); val |= BIT0(combined) << bit; } *--output = val; }while (--len > 0);}/* * This encryption engine implements one of 32 variations * one the same theme depending upon the choice in the * varient parameter (0 - 31). * * The algorithm itself manipulates a 40 bit input into * a 40 bit output. * The parameter 'input' is 80 bits. It consists of * the 40 bit input value that is to be encrypted followed * by a 40 bit seed value for the pseudo random number * generators. */static void css_engine(int varient, unsigned char const *input, struct mpeg3_block *output){ unsigned char cse, term, index; struct mpeg3_block temp1; struct mpeg3_block temp2; unsigned char bits[30]; int i;/* Feed the secret into the input values such that * we alter the seed to the LFSR's used above, then * generate the bits to play with. */ for(i = 5; --i >= 0; ) temp1.b[i] = input[5 + i] ^ mpeg3css_secret[i] ^ mpeg3css_table2[i]; generate_bits(&bits[29], sizeof bits, &temp1); /* This term is used throughout the following to * select one of 32 different variations on the * algorithm. */ cse = mpeg3css_varients[varient] ^ mpeg3css_table2[varient]; /* Now the actual blocks doing the encryption. Each * of these works on 40 bits at a time and are quite * similar. */ for(i = 5, term = 0; --i >= 0; term = input[i]) { index = bits[25 + i] ^ input[i]; index = mpeg3css_table1[index] ^ ~mpeg3css_table2[index] ^ cse; temp1.b[i] = mpeg3css_table2[index] ^ mpeg3css_table3[index] ^ term; } temp1.b[4] ^= temp1.b[0]; for(i = 5, term = 0; --i >= 0; term = temp1.b[i]) { index = bits[20 + i] ^ temp1.b[i]; index = mpeg3css_table1[index] ^ ~mpeg3css_table2[index] ^ cse; temp2.b[i] = mpeg3css_table2[index] ^ mpeg3css_table3[index] ^ term; } temp2.b[4] ^= temp2.b[0]; for (i = 5, term = 0; --i >= 0; term = temp2.b[i]) { index = bits[15 + i] ^ temp2.b[i]; index = mpeg3css_table1[index] ^ ~mpeg3css_table2[index] ^ cse; index = mpeg3css_table2[index] ^ mpeg3css_table3[index] ^ term; temp1.b[i] = mpeg3css_table0[index] ^ mpeg3css_table2[index]; } temp1.b[4] ^= temp1.b[0]; for (i = 5, term = 0; --i >= 0; term = temp1.b[i]) { index = bits[10 + i] ^ temp1.b[i]; index = mpeg3css_table1[index] ^ ~mpeg3css_table2[index] ^ cse; index = mpeg3css_table2[index] ^ mpeg3css_table3[index] ^ term; temp2.b[i] = mpeg3css_table0[index] ^ mpeg3css_table2[index]; } temp2.b[4] ^= temp2.b[0]; for (i = 5, term = 0; --i >= 0; term = temp2.b[i]) { index = bits[5 + i] ^ temp2.b[i]; index = mpeg3css_table1[index] ^ ~mpeg3css_table2[index] ^ cse; temp1.b[i] = mpeg3css_table2[index] ^ mpeg3css_table3[index] ^ term; } temp1.b[4] ^= temp1.b[0]; for (i = 5, term = 0; --i >= 0; term = temp1.b[i]) { index = bits[i] ^ temp1.b[i]; index = mpeg3css_table1[index] ^ ~mpeg3css_table2[index] ^ cse; output->b[i] = mpeg3css_table2[index] ^ mpeg3css_table3[index] ^ term; }}static void crypt_key1(mpeg3_css_t *css, int varient, unsigned char const *challenge, struct mpeg3_block *key){ static unsigned char perm_challenge[] = {1, 3, 0, 7, 5, 2, 9, 6, 4, 8}; unsigned char scratch[10]; int i; for (i = 9; i >= 0; i--) scratch[i] = challenge[perm_challenge[i]]; css_engine(varient, scratch, key);}/* This shuffles the bits in varient to make perm_varient such that * 4 -> !3 * 3 -> 4 * varient bits: 2 -> 0 perm_varient bits * 1 -> 2 * 0 -> !1 */static void crypt_key2(mpeg3_css_t *css, int varient, unsigned char const *challenge, struct mpeg3_block *key){ static unsigned char perm_challenge[] = {6, 1, 9, 3, 8, 5, 7, 4, 0, 2}; static unsigned char perm_varient[] = { 0x0a, 0x08, 0x0e, 0x0c, 0x0b, 0x09, 0x0f, 0x0d, 0x1a, 0x18, 0x1e, 0x1c, 0x1b, 0x19, 0x1f, 0x1d, 0x02, 0x00, 0x06, 0x04, 0x03, 0x01, 0x07, 0x05, 0x12, 0x10, 0x16, 0x14, 0x13, 0x11, 0x17, 0x15 }; unsigned char scratch[10]; int i; for(i = 9; i >= 0; i--) scratch[i] = css->challenge[perm_challenge[i]]; css_engine(perm_varient[varient], scratch, key);}/* This shuffles the bits in varient to make perm_varient such that * 4 -> 0 * 3 -> !1 * varient bits: 2 -> !4 perm_varient bits * 1 -> 2 * 0 -> 3 */static void crypt_bus_key(mpeg3_css_t *css, int varient, unsigned char const *challenge, struct mpeg3_block *key){ static unsigned char perm_challenge[] = {4,0,3,5,7, 2,8,6,1,9}; static unsigned char perm_varient[] = { 0x12, 0x1a, 0x16, 0x1e, 0x02, 0x0a, 0x06, 0x0e, 0x10, 0x18, 0x14, 0x1c, 0x00, 0x08, 0x04, 0x0c, 0x13, 0x1b, 0x17, 0x1f, 0x03, 0x0b, 0x07, 0x0f, 0x11, 0x19, 0x15, 0x1d, 0x01, 0x09, 0x05, 0x0d}; unsigned char scratch[10]; int i; for(i = 9; i >= 0; i--) scratch[i] = css->challenge[perm_challenge[i]]; css_engine(perm_varient[varient], scratch, key);}static int get_asf(mpeg3_css_t *css){ dvd_authinfo ai; ai.type = DVD_LU_SEND_ASF; ai.lsasf.agid = 0; ai.lsasf.asf = 0; if(ioctl(css->fd, DVD_AUTH, &ai)) {/* Exit here for a hard drive or unencrypted CD-ROM. */ return 1; } return 0;}static int authenticate_drive(mpeg3_css_t *css, const unsigned char *key){ int i; for(i = 0; i < 5; i++) css->key1.b[i] = key[4 - i]; for(i = 0; i < 32; ++i) { crypt_key1(css, i, css->challenge, &(css->keycheck)); if(memcmp(css->keycheck.b, css->key1.b, 5) == 0) { css->varient = i; return 0; } } if (css->varient == -1) return 1; return 0;}/* Simulation of a non-CSS compliant host (i.e. the authentication fails, * but idea is here for a real CSS compliant authentication scheme). */static int hostauth(mpeg3_css_t *css, dvd_authinfo *ai){ int i; switch(ai->type) {/* Host data receive (host changes state) */ case DVD_LU_SEND_AGID: ai->type = DVD_HOST_SEND_CHALLENGE; break; case DVD_LU_SEND_KEY1:/* printf("Key 1: %02x %02x %02x %02x %02x\n", *//* ai->lsk.key[4], ai->lsk.key[3], ai->lsk.key[2], ai->lsk.key[1], ai->lsk.key[0]); */ if(authenticate_drive(css, ai->lsk.key)) { ai->type = DVD_AUTH_FAILURE; return 1; } ai->type = DVD_LU_SEND_CHALLENGE; break; case DVD_LU_SEND_CHALLENGE: for(i = 0; i < 10; i++) css->challenge[i] = ai->hsc.chal[9-i]; crypt_key2(css, css->varient, css->challenge, &(css->key2)); ai->type = DVD_HOST_SEND_KEY2; break;/* Host data send */ case DVD_HOST_SEND_CHALLENGE: for(i = 0; i < 10; i++) ai->hsc.chal[9 - i] = css->challenge[i];/* Returning data, let LU change state */ break; case DVD_HOST_SEND_KEY2: for(i = 0; i < 5; i++) { ai->hsk.key[4 - i] = css->key2.b[i]; }/* printf("Key 2: %02x %02x %02x %02x %02x\n", *//* ai->hsk.key[4], ai->hsk.key[3], ai->hsk.key[2], ai->hsk.key[1], ai->hsk.key[0]); *//* Returning data, let LU change state */ break; default: fprintf(stderr, "Got invalid state %d\n", ai->type); return 1; } return 0;}static int get_title_key(mpeg3_css_t *css, int agid, int lba, unsigned char *key){ dvd_authinfo ai; int i; ai.type = DVD_LU_SEND_TITLE_KEY; ai.lstk.agid = agid; ai.lstk.lba = lba; if(ioctl(css->fd, DVD_AUTH, &ai)) { //perror("GetTitleKey"); return 1; } for (i = 0; i < 5; i++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -