📄 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 + -