📄 nagra2.c
字号:
/* * 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 "system.h"#include "misc.h"#include "opts.h"#include "network.h"#include "crypto.h"#include "helper.h"#include <openssl/des.h>#include <openssl/sha.h>#include "openssl-compat.h"#include "nagra.h"#include "cpu.h"#include "log-nagra.h"#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;}// -- cMapCore -----------------------------------------------------------------#define SETSIZE 0x02#define IMPORT_J 0x03#define IMPORT_A 0x04#define IMPORT_B 0x05#define IMPORT_C 0x06#define IMPORT_D 0x07#define EXPORT_A 0x0A#define EXPORT_B 0x0B#define EXPORT_C 0x0C#define EXPORT_D 0x0Dclass 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: PRINTF(L_GEN_DEBUG,"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: PRINTF(L_GEN_DEBUG,"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 SHA1_Init(&sctx); break; case 0x44: // add 64 bytes to SHA1 buffer RotateBytes(data,64); SHA1_Update(&sctx,data,64); BYTE4_LE(data ,sctx.h4); BYTE4_LE(data+4 ,sctx.h3); BYTE4_LE(data+8 ,sctx.h2); BYTE4_LE(data+12,sctx.h1); BYTE4_LE(data+16,sctx.h0); break; case 0x45: // add wordsize bytes to SHA1 buffer and finalize SHA result if(wordsize) { if(wordsize>1) RotateBytes(data,wordsize); SHA1_Update(&sctx,data,wordsize); } memset(data,0,64); SHA1_Final(data+64,&sctx); break; default: return false; } 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 ProcessBx(unsigned char *data, int len, int pos) { return -1; } virtual bool PostProcAU(int id, unsigned char *data) { return true; } 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_Bx 2#define N2FLAG_POSTAU 4#define N2FLAG_INV 128class 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){ PRINTF(L_CORE_DYN,"n2providers: registering prov %04X with flags %d",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);}#include "nagra2-prov.c"#ifndef TESTER// -- cNagra2 ------------------------------------------------------------------class cNagra2 : public cNagra {private: bool Signature(const unsigned char *vkey, const unsigned char *sig, const unsigned char *msg, int len);protected: cIDEA idea; // virtual void CreatePQ(const unsigned char *key, BIGNUM *p, BIGNUM *q); bool DecryptECM(const unsigned char *in, unsigned char *out, const unsigned char *key, int len, const unsigned char *vkey, BIGNUM *m); bool DecryptEMM(const unsigned char *in, unsigned char *out, const unsigned char *key, int len, const unsigned char *vkey, BIGNUM *m); };void cNagra2::CreatePQ(const unsigned char *key, BIGNUM *p, BIGNUM *q){ // Calculate P and Q from PK IdeaKS ks; idea.SetEncKey(key,&ks); // expand IDEA-G key unsigned char idata[96]; for(int i=11; i>=0; i--) { unsigned char *d=&idata[i*8]; memcpy(d,&key[13],8); *d^=i; idea.Decrypt(d,8,&ks,0); xxor(d,8,d,&key[13]); *d^=i; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -