📄 nagra2.cpp
字号:
/*
* Softcam plugin to VDR (C++)
*
* This code 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 code 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <unistd.h>
#include <ctype.h>
#include "stdafx.h"
//#include <vdr/tools.h>
#include "common.h"
#include "sc.h"
#include "system.h"
#include "misc.h"
#include "opts.h"
#include "network.h"
#include "crypto.h"
//#include "md5crypt/md5crypt.h"
#include "helper.h"
/////////
#include "network.h"
#include "xnprintf.h"
#include <openssl/bn.h>
#include <openssl/des.h>
#include <openssl/sha.h>
#include "openssl-compat.h"
#include "debug.h"
#include "nagra.h"
#include "cpu.h"
//******************************************** Modification - 12/26/06 **
#include "main.h"
extern class DllClass m_DLLInstance;
extern bool g_BeepOnNewKey;
extern bool g_LogE3;
//#include "morph.h"
//extern class B1morph B1_morph;
//******************************************** Modification - 12/26/06 **
#define SYSTEM_NAME "Nagra2"
#define SYSTEM_PRI -10
// -- cN2Emu -------------------------------------------------------------------
class cN2Emu : protected c6805 {
private:
bool initDone;
protected:
bool Init(int id, int romv);
virtual void Stepper(void) {}
public:
cN2Emu(void);
virtual ~cN2Emu() {}
};
cN2Emu::cN2Emu(void)
{
initDone=false;
}
bool cN2Emu::Init(int id, int romv)
{
if(!initDone) {
ResetMapper();
char buff[256];
_snprintf(buff,sizeof(buff),"ROM%d.bin",romv);
// UROM 0x00:0x4000-0x7fff
if(!AddMapper(new cMapRom(0x4000,buff,0x00000),0x4000,0x4000,0x00)) return false;
// ROM00 0x00:0x8000-0xffff
if(!AddMapper(new cMapRom(0x8000,buff,0x04000),0x8000,0x8000,0x00)) return false;
// ROM01 0x01:0x8000-0xffff
if(!AddMapper(new cMapRom(0x8000,buff,0x0C000),0x8000,0x8000,0x01)) return false;
// ROM02 0x02:0x8000-0xbfff
if(!AddMapper(new cMapRom(0x8000,buff,0x14000),0x8000,0x4000,0x02)) return false;
_snprintf(buff,sizeof(buff),"EEP%02X_%d.bin",(id>>8)&0xFF,romv);
// Eeprom00 0x00:0x3000-0x37ff OTP 0x80
if(!AddMapper(new cMapRom(0x3000,buff,0x0000),0x3000,0x0800,0x00)) return false;
//XXX if(!AddMapper(new cMapEeprom(0x3000,buff,128,0x0000),0x3000,0x0800,0x00)) return false;
// Eeprom80 0x80:0x8000-0xbfff
if(!AddMapper(new cMapRom(0x8000,buff,0x0800),0x8000,0x4000,0x80)) return false;
//XXX if(!AddMapper(new cMapEeprom(0x8000,buff, 0,0x0800),0x8000,0x4000,0x80)) return false;
initDone=true;
}
return true;
}
// -- cN2Prov ------------------------------------------------------------------
class cN2Prov {
private:
unsigned seed[5], cwkey[8];
bool keyValid;
cIDEA idea;
protected:
int id, flags;
//
virtual bool Algo(int algo, const unsigned char *hd, unsigned char *hw) { return false; }
virtual bool NeedsCwSwap(void) { return false; }
void ExpandInput(unsigned char *hw);
public:
cN2Prov(int Id, int Flags);
virtual ~cN2Prov() {}
bool MECM(unsigned char in15, int algo, unsigned char *cws);
void SwapCW(unsigned char *cw);
virtual int ProcessB1(unsigned char *data, int len, int pos) { return -1; }
bool CanHandle(int Id) { return ((Id^id)&~0x107)==0; }
bool HasFlags(int Flags) { return (flags&Flags)==Flags; }
};
cN2Prov::cN2Prov(int Id, int Flags)
{
keyValid=false; id=Id; flags=Flags;
}
void cN2Prov::ExpandInput(unsigned char *hw)
{
hw[0]^=(0xDE +(0xDE<<1)) & 0xFF;
hw[1]^=(hw[0]+(0xDE<<1)) & 0xFF;
for(int i=2; i<128; i++) hw[i]^=hw[i-2]+hw[i-1];
IdeaKS ks;
idea.SetEncKey((unsigned char *)"NagraVision S.A.",&ks);
unsigned char buf[8];
memset(buf,0,8);
for(int i=0; i<128; i+=8) {
xxor(buf,8,buf,&hw[i]);
idea.Encrypt(buf,8,buf,&ks,0);
xxor(buf,8,buf,&hw[i]);
memcpy(&hw[i],buf,8);
}
}
bool cN2Prov::MECM(unsigned char in15, int algo, unsigned char *cw)
{
unsigned char hd[5], hw[128+64], buf[20];
hd[0]=in15&0x7F;
hd[1]=cw[14];
hd[2]=cw[15];
hd[3]=cw[6];
hd[4]=cw[7];
if(keyValid && !memcmp(seed,hd,5)) { // key cached
memcpy(buf,cwkey,8);
}
else { // key not cached
memset(hw,0,sizeof(hw));
if (!Algo(algo,hd,hw)) return false;
memcpy(&hw[128],hw,64);
RotateBytes(&hw[64],128);
SHA1(&hw[64],128,buf);
RotateBytes(buf,20);
memcpy(seed,hd,5);
memcpy(cwkey,buf,8);
keyValid=true;
}
memcpy(&buf[8],buf,8);
IdeaKS ks;
idea.SetEncKey(buf,&ks);
memcpy(&buf[0],&cw[8],6);
memcpy(&buf[6],&cw[0],6);
idea.Encrypt(&buf[4],8,&buf[4],&ks,0);
idea.Encrypt(buf,8,buf,&ks,0);
memcpy(&cw[ 0],&buf[6],3);
memcpy(&cw[ 4],&buf[9],3);
memcpy(&cw[ 8],&buf[0],3);
memcpy(&cw[12],&buf[3],3);
for(int i=0; i<16; i+=4) cw[i+3]=cw[i]+cw[i+1]+cw[i+2];
return true;
}
void cN2Prov::SwapCW(unsigned char *cw)
{
if(NeedsCwSwap()) {
unsigned char tt[8];
memcpy(&tt[0],&cw[0],8);
memcpy(&cw[0],&cw[8],8);
memcpy(&cw[8],&tt[0],8);
}
}
// -- cN2ProvLink & cN2Providers -----------------------------------------------
#define N2FLAG_NONE 0
#define N2FLAG_MECM 1
#define N2FLAG_B1 2
#define N2FLAG_INV 128
class cN2Providers;
class cN2ProvLink {
friend class cN2Providers;
private:
cN2ProvLink *next;
protected:
int id, flags;
//
virtual cN2Prov *Create(void)=0;
bool CanHandle(int Id) { return ((Id^id)&~0x107)==0; }
bool HasFlags(int Flags) { return (flags&Flags)==Flags; }
public:
cN2ProvLink(int Id, int Flags);
virtual ~cN2ProvLink() {}
};
class cN2Providers {
friend class cN2ProvLink;
private:
static cN2ProvLink *first;
//
static void Register(cN2ProvLink *plink);
public:
static cN2Prov *GetProv(int Id, int Flags);
};
template<class PROV, int ID, int FLAGS> class cN2ProvLinkReg : public cN2ProvLink {
public:
cN2ProvLinkReg(void):cN2ProvLink(ID,FLAGS) {}
virtual cN2Prov *Create(void) { return new PROV(id,flags); }
};
cN2ProvLink *cN2Providers::first=0;
void cN2Providers::Register(cN2ProvLink *plink)
{
dyn(printf("n2providers: registering prov %04X with flags %d\n",plink->id,plink->flags))
plink->next=first;
first=plink;
}
cN2Prov *cN2Providers::GetProv(int Id, int Flags)
{
cN2ProvLink *pl=first;
while(pl) {
if(pl->CanHandle(Id) && pl->HasFlags(Flags)) return pl->Create();
pl=pl->next;
}
return 0;
}
cN2ProvLink::cN2ProvLink(int Id, int Flags)
{
id=Id; flags=Flags;
cN2Providers::Register(this);
}
class cMapCore {
private:
cBN x, y, s, j;
SHA_CTX sctx;
protected:
cBN A, B, C, D, J;
cBN H, R;
cBNctx ctx;
int wordsize;
//
void ImportReg(unsigned char reg, const unsigned char *data, int l=0);
void ExportReg(unsigned char reg, unsigned char *data, int l=0, bool BE=false);
void SetWordSize(int l) { wordsize=l; }
void MakeJ(void);
void MonMul(BIGNUM *o, BIGNUM *i1, BIGNUM *i2);
bool DoMap(int f, unsigned char *data=0, int l=0);
public:
cMapCore(void);
};
cMapCore::cMapCore(void)
{
wordsize=4;
}
void cMapCore::ImportReg(unsigned char reg, const unsigned char *in, int l)
{
l=(l?l:wordsize)<<3;
switch(reg) {
case IMPORT_J: J.GetLE(in,8); break;
case IMPORT_A: A.GetLE(in,l); break;
case IMPORT_B: B.GetLE(in,l); break;
case IMPORT_C: C.GetLE(in,l); break;
case IMPORT_D: D.GetLE(in,l); break;
default: d(printf("internal: nagramap import register not supported")); return;
}
}
void cMapCore::ExportReg(unsigned char reg, unsigned char *out, int l, bool BE)
{
l=(l?l:wordsize)<<3;
cBN *ptr;
switch(reg) {
case EXPORT_A: ptr=&A; break;
case EXPORT_B: ptr=&B; break;
case EXPORT_C: ptr=&C; break;
case EXPORT_D: ptr=&D; break;
default: d(printf("internal: nagramap export register not supported")); return;
}
if(!BE) ptr->PutLE(out,l);
else ptr->Put(out,l);
}
void cMapCore::MakeJ(void)
{
#if OPENSSL_VERSION_NUMBER < 0x0090700fL
#error BN_mod_inverse is probably buggy in your openssl version
#endif
BN_zero(x);
BN_sub(J,x,D);
BN_set_bit(J,0);
BN_set_bit(x,64);
BN_mod_inverse(J,J,x,ctx);
}
void cMapCore::MonMul(BIGNUM *o, BIGNUM *i1, BIGNUM *i2)
{
int words=(BN_num_bytes(i1)+7)>>3;
BN_zero(s);
for(int i=0; i<words; i++) {
BN_rshift(x,i1,i<<6);
BN_mask_bits(x,64);
BN_mul(x,x,i2,ctx);
BN_add(s,s,x);
BN_copy(x,s);
BN_mask_bits(x,64);
BN_mul(x,x,J,ctx);
if(i==(words-1)) {
BN_lshift(y,x,64);
BN_add(y,y,x);
// Low
BN_rshift(C,y,2);
BN_add(C,C,s);
BN_rshift(C,C,52);
BN_mask_bits(C,12);
}
BN_mask_bits(x,64);
BN_mul(x,x,D,ctx);
BN_add(s,s,x);
if(i==(words-1)) {
// High
BN_lshift(y,s,12);
BN_add(C,C,y);
BN_mask_bits(C,wordsize<<6);
}
BN_rshift(s,s,64);
if(BN_cmp(s,D)==1) {
BN_copy(x,s);
BN_sub(s,x,D);
}
}
BN_copy(o,s);
}
bool cMapCore::DoMap(int f, unsigned char *data, int l)
{
switch(f) {
case 0x43: // init SHA1
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -