Code:
/*********************************************************************
File: GoM V3.5.4 (Based all on FoM-FunSECA)
Author: Gribley
Dates: Nov2001 - May 2002
Purpose: SECA emulation :p
Compiler: AVR-GCC + Make2
Hardware: FunCard 8515 or, with mod to Makefile, 8535
**********************************************************************/
#include <io.h>
#include "types.h"
// Using intelli byte we can add additional space
// to any calls to the upper end of the eeprom
// this therefore allows us to have a single
// version that supports Funcard 2, 3 and 4... this value
// is added to the upper limit of the eeprom
u16 Extra_Funcard_Space = 0x0000;
// Default serial number
//u08 DefaultSerial[3] = {0xF2, 0xF1, 0xF0};
#include "funseca.h"
#include "funio.h"
#include "decrip.h"
#include "ee_ext.h"
#include "ee_int.h"
#define MODO_LOG = 0x01
u08 ECM_Count_High = 0x00;
u08 ECM_Count_Low = 0x00;
u08 ECM_LastECMInst = 0x00;
u08 ECM_LastProviderChecked = 0x00;
//u08 EVENT_Display[16] = {0xD3,0xC7,0xAE,0xFD,0x2B,0x8E,0x91,0x35,
// 0xC4,0x81,0xC0,0xE4,0xB3,0x09,0xD4,0x0B};
u08 EVENT_Display[12] = {'C','W','P',':','0','0',' ','E',
'V','N','T',':'};
//u08 ECM_Display[16] = {0x6A,0x81,0x60,0x2A,0x12,0xA7,0x38,0x8E,
// 0x66,0xD1,0xCB,0x82,0x6C,0xAC,0xB9,0x09};
u08 ECM_Display[12] = {'I','N','S',':','0','0',' ','E',
'C','M','s',':'};
// Display LOG ON in provider 4 when logging is enabled.
u08 LOG_Method = 0x00;
u08 LOG_ON[6] = {'L','o','g',' ','O','N'};
u08 LOG_Mode_0[4] = {'L','o','o','p'};
u08 LOG_Mode_1[4] = {'S','t','o','p'};
#define MAX_COMMAND_LENGHT 0x5F // (+5 de la cabecera = 0x5f)
// Buffer of entrance and exit
u08 buffer[MAX_COMMAND_LENGHT];
// This is just an experiement!
u08 ProviderCount = 0x00;
// current Provider, currentKey & current Channel for info mode
u08 currentProvider = 0x01;
u08 currentKey = 0x00;
// PPV auto - with CapturePPVEvent now watching for lack of 3c\3a receipt
// i.e. Porn, this should then default to using SelectSelect mode.
//u08 CapturePPVEvent = 0x00;
u08 EventUpdatedin3C = FALSE;
u08 OldStylePPV = FALSE;
// Data for the Inst 0x0A: Operating system of the card
#define TOTAL_VERSION 68
u08 version[TOTAL_VERSION]= {
0x61,0x19,0xad,0xca,0x15,0x2f,0x10,0x03,
0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x9E,
0xB9,0xDF,0x34,0x94,0xEF,0x3E,0x00,0x13,
0x3A,0x57,0x12,0x53,0x84,0x1A,0xD5,0x90,
0x14,0x10,0x31,0x2C,0xDA,0xC8,0xAD, '5',
'4' ,'=' ,'-' ,0x00 };
//u08 gribomatic[16] = {'G','-','o','-','M',' ','V','3',
// 'x','x',' ','(','N','A',')',' '};
u08 gribomatic[16] = {0x9B,0x65,0xBB,0x32,0x07,0x10,0xF2,0x32,
0x36,0xB4,0xD4,0xCC,0x86,0x2B,0xB5,0x1D};
// Encrypted strings you easy use :)
// If nothing else it should stop Mr PurpleHaze
// Standard version 3 -> 0x9B,0x65,0xBB,0x32,0x07,0x10,0xF2,0x32,
// Beta\private version 3 -> 0x8E,0xDA,0xB3,0xFC,0xB0,0x6E,0x98,0x13,
// 353 string -> 0x14,0xCC,0x61,0xF4,0xE6,0x84,0x07,0xC9};
// 354 string -> 0x36,0xB4,0xD4,0xCC,0x86,0x2B,0xB5,0x1D};
// PPV BX record, generate event and session details on the fly....
u08 ppv_record[14] = {0xB1,0x00,0xFF,0xFF,0x01,0xFE,0x05,0x00,0x00,0xFF,0xFF,0x00,0x00,0x04};
// Record last requested in 0x34,0x32 pair
//u08 ppv_request[2] = {0x00,0x00};
#define EVENT_ID1 2
#define EVENT_ID2 3
#define SESSION_ID 4
#define SESSION_DATE1 9
#define SESSION_DATE2 10
// Punteros a las funciones de comunicación
void (*ptrSend)(u08);
u08 (*ptrReceive) (void);
// stores the last processed instruction
u08 lastInst = 0x00;
// Only show my info if last command was not a 3c or 3a request
u08 LastNonProviderInst = 0x00;
// Allows to use phoenix to make operations of external I/O eeprom.
u08 support_phoenix = TRUE;
// PAra the cloqueo of ticket offices
u08 decodeX = FALSE;
u08 needPin = TRUE;
u08 pinChecked = FALSE;
// Answer to Reset
// It indicates that the card is a version 4,1 (original FoM 4.0)
u08 ATR[16]={0x3B,0xF7,0x11,0x00,0x01,0x40,0x96,0x58,
0x42,0x14,0x0E,0x6C,0xB6,0xD6,0x90,0x00};
// key in use (PK + SK)
u08 Key[8+8];
// hash-buffers for the verification of the signature
u08 hash[8];
u08 initial_hash[8];
// ControlWords desencriptadas para la 0x3A
u08 CW[8+8];
// command sent by 0x34 and 0x38
u08 Comando34[5];
// status bytes
u08 sw1=0x90,sw2=0x00;
// PPV Cache vars
u08 NextEvent=0;
u08 lLastProvider=0;
u08 CommandCountDown=60;
u08 EventInCache(u08 evnt1, u08 evnt2)
{
u08 i;
for (i=0; i<32; i=i+2){
if (evnt1==version[i] && evnt2==version[i+1]){
// Event is known :)
return 1;
}
}
return 0;
}
void AddPPVEvent(u08 evnt1, u08 evnt2)
{
if (!EventInCache(evnt1,evnt2)){
// Move the event marker onwards
version[NextEvent++]=evnt1;
version[NextEvent++]=evnt2;
// Start to overwrite from the start once again
if (NextEvent>31){
// Back to the start
NextEvent=0;
}
}
}
void IncrementECMCount(u08 inst)
{
// Only increment ECM count when card has been initalised in the STB
if (!support_phoenix){
ECM_LastECMInst = inst;
if (ECM_Count_Low==0xff){
if (ECM_Count_High<0xff){ECM_Count_High++;}
ECM_Count_Low=0x00;
} else
ECM_Count_Low++;
}
}
void sendString(u08 *str, u08 len)
{
do { (*ptrSend)(*str++); } while (--len);
}
void receiveString(u08 len)
{
u08 *dst=buffer;
do { *dst++ = (*ptrReceive)(); } while (--len);
}
void fillBuffer(u08 begin_idx ,u08 end_idx, u08 fillByte)
{
u08 cnt;
for (cnt=begin_idx; cnt<end_idx; cnt++)
buffer[cnt]=fillByte;
}
void _memcpy(u08 *dst,u08 *src,u08 n)
{
while(n){
*dst=*src;
dst++;
src++;
n--;
}
}
u16 getProvAddr(u08 p1)
{
u16 res;
p1 &= 0x0f;
for (res = EE_ENTETY_0; p1; p1--)
res += EE_ENTETY_SIZE;
return res;
}
u16 getPKAddr(u08 p1, u08 p2)
{
u16 key_offset = getProvAddr(p1) + EE_ENT_KEY_0;
//key_index*=8, at908515 opt, lose the bit 7 (superencription)
p2 <<= 1; p2 <<= 1; p2 <<= 1;
return (key_offset + p2);
}
void decode(u08 p2, u08 len)
{
u08 *src=buffer;
if (p2&0x80){
while (len>8){
decrip(Key,src);
len-=8;
src+=8;
}
}
}
void getKey(u08 p1, u08 p2)
{
u16 key_offset=getPKAddr(p1,p2);
ee_readString(Key,key_offset,8);
ee_readString(Key+8,(p1&0x10)?key_offset+(16*8):key_offset,8);
}
u08 xor_hash(u08 len, u08 r)
{
u08 cnt;
decrip(Key,hash);
len-=r;
for (cnt=0; cnt<r; cnt++)
hash[cnt]^=buffer[len+cnt];
return len;
}
u08 signaturePresent(u08 siglen)
{
// Grib - Length has to be at least 9 (82 plus sig)
if (siglen>0x08){
if (buffer[siglen-0x09]==0x82){
// Signature is present
return 1;
}
}
// Too short of signature missing
return 0;
}
u08 signatureCheck(u08 p1, u08 len)
{
u08 cnt;
u08 resto=len&7;
u16 addr;
// Grib - Length has to be at least 9 (82 plus sig)
if (!signaturePresent(len)){
return 0;
}
//if (len<9)
// return 0;
len-=8; // indice al nano 0x82
//if (buffer[len-1]!=0x82)
// return 0;
_memcpy(hash,buffer+len,8);
// I calculate inverse of the company/signature
if (resto){
len=xor_hash(len,resto);
}
while (len>0){
len=xor_hash(len,8);
}
// To calculate initial hashbuffer
for (cnt=0; cnt<8; cnt++){
initial_hash[cnt]=0;
}
addr=getProvAddr(p1) + EE_ENT_PPUA;
p1&=0xE0;
if (p1==0x20){
// UA + 00 00
ee_readString(initial_hash, EE_NUM_TARJETA,6);
} else if (p1==0x40){
// PPUA + 00 00 00 00
ee_readString(initial_hash,addr,4);
} else if (p1==0x60){
// SA + 00 00 00 00 00
ee_readString(initial_hash,addr,3);
}
// If hash signs correct - > calculated buffer = hash initial buffer
for (cnt=0; cnt<8; cnt++){
if (initial_hash[cnt]!=hash[cnt])
return 0;
}
return 1;
}
void updateKey(u08 idx, u08 p1, u08 sk)
{
u16 addr;
// to desencriptar the key
_memcpy(CW,&buffer[idx+2],8);
decrip(Key,CW);
// to calculate direction
addr=getPKAddr(p1,(buffer[idx+1]&0x0F));
addr=sk?(addr+(16*8)):addr;
// to update if it is different from the stored one
ee_updateString(addr,CW,8);
}
u08 keyExist(u08 p1, u08 p2)
{
// 0x00 if the key does not exist
// 0x50 if only PK
// 0xf0 if also SK (note: the PK can be 8*0x00)
u08 cnt,res=0x00;
// Cargar Pk&Sk
getKey(p1|0x10,p2);
for (cnt=0; cnt<16; cnt++){
if (Key[cnt]){
if (cnt<8)
res=0x50;
else res=0xf0;
}
}
return res;
}
u08 nibble2ascii(u08 nibble)
{
// Changed to go lower case for the 'keylog' stuff later on
return (nibble<0x0a)?(nibble+'0'):(nibble+('a'-0x0a));
}
void byte2ascii(u08 value, u08 idx)
{
u08 *dst=&buffer[idx];
*dst++=nibble2ascii(value>>4);
*dst=nibble2ascii(value&0x0f);
}
void antipurple(u08 offset, u08 repeat)
{
u08 i;
// Antipurple decrypts the contents in the buffer
// at a given offset x the number of 8byte blocks
for (i=0; i<16; i++){
Key[i]=i%0x0d;
}
for (i=0; i<repeat; i++){
decrip(Key,buffer+(offset+(8*i)));
}
}
#ifdef MODO_LOG
#include "log.h"
#endif
void setupInfo(u08 p1, u08 p3)
{
u16 addr;
u08 i; //j,n;
if (p1!=++ECM_LastProviderChecked){
// Not in sequence!
LastNonProviderInst=0x12;
}
// Check provider index ANTI-ECM method
if ((p1 & 0x0F)>=ProviderCount && currentKey && (LastNonProviderInst!=0x3a || p3!=0x18)){
// We are faking the number of providers.
LastNonProviderInst=0x12;
sw2=0x04;
return;
}
// Stick in the real provider details
addr = getProvAddr(p1);
// Ident
ee_readString(buffer,addr,2);
// To fill up with spaces field names
fillBuffer(2,(2+16),0x20);
//addr = getProvAddr(CurrentProvider);
// PPUA + Date
ee_readString(buffer+(2+16),addr + EE_ENT_PPUA, 4+2);
// Grib - adding region to the return
ee_readString(buffer+(23+1),addr + EE_ENT_REGION,1);
p1&=0x0f;
if (p1==0x00 || LastNonProviderInst!=0x3a || p3!=0x18){
LastNonProviderInst=0x12;
// Provider name in buffer[2..18]
ee_readString(buffer + 2, addr + EE_ENT_NAME, 16);
// PPUA + Date
// done above -> ee_readString(buffer+(2+16),addr + EE_ENT_PPUA,4+2);
if (!p1){
// Just clear the seca date....
_memcpy(buffer+(2+16+4+1),0x00,1);
}
} else
if (p1==0x01){
_memcpy(buffer+(2),gribomatic,16);
// Need to decrypt the my key now.... waster mr PurpleHaze
antipurple(2,2);
// Display the current Opkey
byte2ascii(currentKey,14);
// And the method of PPV
buffer[17]=(OldStylePPV)?'M':'A';
} else
if (p1==0x02){
// Use provider 2 for event and custWP :)
_memcpy(buffer+(2),EVENT_Display,12);
//antipurple(2,2);
byte2ascii(ee_read(getProvAddr(currentProvider)+(EE_ENT_PPUA + 3)),6);
byte2ascii(ppv_record[EVENT_ID1],14);
byte2ascii(ppv_record[EVENT_ID2],16);
} else
if (p1==0x03){
// Use provider 3 as a general ECM display :)
_memcpy(buffer+(2),ECM_Display,12);
//antipurple(2,2);
byte2ascii(ECM_LastECMInst,6);
byte2ascii(ECM_Count_High,14);
byte2ascii(ECM_Count_Low,16);
} else
if (p1==0x04){
// Bit of a KeyLog rip off, show only the opkey
// that is not in use :p
if (modo_log){
_memcpy(buffer+(2),LOG_ON,6);
if (LOG_Method){
// Loop at end of eeprom
_memcpy(buffer+(9),LOG_Mode_1,4);
} else {
// Stop at end of eeprom
_memcpy(buffer+(9),LOG_Mode_0,4);
}
} else {
if (currentKey==0x0c){
addr=getPKAddr(currentProvider, 0x0d);
} else {
addr=getPKAddr(currentProvider, 0x0c);
}
for(i=0; i<8; i++){
byte2ascii(ee_read(addr + i),2+2*i);
}
}
} else {
// Provider name in buffer[2..18]
ee_readString(buffer + 2, addr + EE_ENT_NAME, 16);
}
}
u08 cardHasExpired(u08 p1, u08 nano_idx, u08 TestDate)
{
u08 expdate_h,expdate_l;
u08 actdate_h,actdate_l;
u08 *ptr;
u16 addr;
// get card expiration date
addr=getProvAddr(p1) + EE_ENT_SUBS_DATE;
expdate_h=ee_read(addr);
expdate_l=ee_read(addr+1);
// get ECM or EMM command date
ptr=&buffer[nano_idx];
actdate_h=*(ptr+1);
actdate_l=*(ptr+2);
// Do we want to check the boundery of the date?... ECM check
if (TestDate){
if (!(actdate_h<expdate_h)){
// Check out the difference between the dates
addr=((actdate_h-expdate_h)*0xff)+(actdate_l-expdate_l);
if (addr>=0x00){
return 1;
}
}
return 0;
}
// else we just see if the card has expired
return (actdate_h>expdate_h || (actdate_h==expdate_h && actdate_l>expdate_l));
}
u08 isCustWPActive(u08 nanof0_idx, u08 custwp)
{
return rightShift(buffer[(nanof0_idx + 32) - rightShift(custwp,3)],custwp&7)&1;
}
u08 TestKey(u08 idx, u08 p1, u08 sk)
{
u16 addr;
u08 res;
// Not the current OpKey so ignore..
// default to bad update until we know better
res=0;
if ((buffer[idx+1]&0x0F)==currentKey){
// to decypt the key
_memcpy(CW,&buffer[idx+2],8);
decrip(Key,CW);
// to calculate base address of the key
addr=getPKAddr(p1,(buffer[idx+1]&0x0F));
addr=sk?(addr+(16*8)):addr;
// Return 1 if already set (this is the "good" result)
res = mem2eeprom_cmp(addr, CW, 8);
//res=ee_TestString(addr,CW,8);
}
return res;
}
u08 processNanos(u08 p1,u08 ECMorEMM, u08 TestOnly)
{
// Current Nano command
u08 nano;
// Position with "buffer"
u08 idx=0;
// Preview PPV or PBM check will activate
u08 rightsAdquired = 0;
// Does more or less the same as rights Aquired!
u08 nanos_13_31 = 2;
// Nbr of nanos processed, returned as part of error in 3c if required
u08 pnanos = 0;
// Store address of target provider
u16 addr;
// Disable porn channels, going via the parental warning nano
u08 nano_2c = 1;
// Flag checks if a d1 nano was present in an ECM
u08 invalid_ECM=0;
// Reused var... various
u08 cnt;
u08 aux1;
u08 aux2;
// Set initial value for 3c check to 1 for ECM
if (ECMorEMM==kECM){
invalid_ECM=1;
//EventUpdatedin3C=FALSE;
}
// Get provider address once outside loop :)
addr = getProvAddr(p1) ;
while (1){
nano = buffer[idx];
// Less flash space to load here instead of references later.
aux1 = buffer[idx+1];
aux2 = buffer[idx+2];
if (nano==0x82){
// ECM 3-Mar-2002
// They are sending through signed 3c instructions
// that do not contain valid nanos
if (TestOnly){
if (!invalid_ECM){
sw2=0x09;
}
return invalid_ECM;
}
if (invalid_ECM){
sw1 = 0x96; sw2 = pnanos;
return 0;
}
pnanos++;
return pnanos;
} else
// ECM nanos - - - - - - - - - - - - - - - - - - - - - - - - - - -
if (ECMorEMM){
// nano 04 : give dw for output OK
// nano 12 : parental control protection ADDED
// nano 13 : verify channel id with provider bitmap package OK
// nano 15 : PPV special management ADDED
// nano 19 : PPV preview control OK
// nano 27 : delete old PPV preview records OK
// nano 2C : PPV tokens management OK
// nano 2D : delete old PPV event records ADDED
// nano 31 : verify PPV event id, diffusion number and vision number OK
// nano 82 : signature OK
// nano D1 : control word to decrypt OK
// nano F1 : bitmap regional code OK
if ((nano==0x04 || nano==0x19) && !rightsAdquired){
// free the channel
if (nano==0x19){sw2=0x27;}
rightsAdquired = 1;
pnanos++;
} else
if (nano==0x13 && !rightsAdquired && nanos_13_31){
// test channel boundle identifier
u08 pbm,bid;
if ((bid=aux1)<64){
//addr=getProvAddr(p1) + (EE_ENT_PBM + 7) - rightShift(bid,3);
//pbm=ee_read(addr);
pbm=ee_read(addr + (EE_ENT_PBM + 7) - rightShift(bid,3));
if (rightShift(pbm,bid&7)&1){
RED_INFO_LED_OFF;
rightsAdquired=1;
}
}
pnanos++;
} else
if (nano==0x12 || nano==0x2d){
pnanos++;
} else
if (nano==0x15){
if (nanos_13_31>0x01){
sw1=0x96; sw2=0;
return 0;
}
pnanos++;
} else
if (nano==0x27 && !rightsAdquired){
// test card expiration date
pnanos++;
// Check for not a Null value in the 0x27
if (aux1|aux2){
if (cardHasExpired(p1,idx,FALSE)){
sw1=0x93; sw2=0x01;
return 0;
}
ppv_record[SESSION_DATE1] = aux1;
ppv_record[SESSION_DATE2] = aux2;
}
} else
if (nano==0x2c && !rightsAdquired){
// x channel
// No pin of perv channels,
if ((aux1|aux2)==0){ // (buffer[idx+1]==0 && buffer[idx+2]==0){
// Null event!
sw1=0x96; sw2=0;
return 0;
}
nano_2c = decodeX;
nanos_13_31--;
} else
if (nano==0x31 && !rightsAdquired && nanos_13_31){
// Check that the PPV event matches the last PPV record
// request offered in the 32/34
if ((aux1|aux2)==0){ // (buffer[idx+1]==0 && buffer[idx+2]==0){
// Null event!
sw1=0x96; sw2=0;
return 0;
}
// Now if the event is in the cache it is bad!
if (CommandCountDown || EventInCache(aux1,aux2)){ // ((ppv_request[0]!=buffer[idx+1] || ppv_request[1]!=buffer[idx+2]) && (!EventInCache(buffer[idx+1],buffer[idx+2]))){
sw2=0x1a;
} else {
ppv_record[SESSION_ID] = buffer[idx+3];
// Add the captured event ID... need to test further!
ppv_record[EVENT_ID1] = aux1;
ppv_record[EVENT_ID2] = aux2;
// Flag for the 34 to determine if an event was received
// EventUpdatedin3C=TRUE;
}
// No longer it is necessary to verify 0x13, 0x31
nanos_13_31--;
pnanos++;
} else
if (nano==0xD1){
pnanos++;
if ((rightsAdquired || !nanos_13_31) && (nano_2c)){
u08 *ptr;
ptr=&buffer[idx+1];
decrip(Key,ptr);
decrip(Key,ptr+8);
_memcpy(CW,ptr,16);
// Contains control word :)
invalid_ECM=0;
} else{
// rights no adquired
sw1=0x93; sw2=0x02;
return 0;
}
} else
if (nano==0xf1){
// Region nano, purpose not really understood... at least by me....
pnanos++;
//addr=getProvAddr(p1) + EE_ENT_REGION;
// Can reuse the custWP check for region check, they
// perform the same actual bit check
if (!isCustWPActive(idx, ee_read(addr + EE_ENT_REGION))){
//IncrementECMCount(0xf1);
sw1=0x93; sw2=0x05;
return 0;
}
}
} // end of ECM nanos
// EMM nanos - - - - - - - - - - - - - - - - - - - - - - - - - - -
else {
// nano 01 : set nano 24 flag to FF
// nano 02 : set nano 24 flag to 00
// nano 03 : delete pin code
// nano 10 : delete given key (primary and secondary)
// nano 11 : delete seca record of a given type
// nano 17 : write regional bitmap
// nano 18 : delete service preview record
// nano 1D : set 8022 eeprom location
// nano 1E : set 8020 eeprom location
// nano 1F : set 8021 eeprom location
// nano 21 : set expiration date
// nano 22 : verify expiration date
// nano 23 : add new provider
// nano 24 : apply next nanos to given provider
// nano 25 : delete given provider
// nano 26 : modify provider space for records and flags
// nano 28 : delete a ppv preview record
// nano 30 : store special credits in ppv credits record
// nano 32 : seek or create record for a given event-id
// nano 33 : create or modify service preview record
// nano 40 : delete ppv event record with event-id between min-max
// nano 41 : set PPUA
// nano 42 : store data and new credits in ppv credits record
// nano 43 : update data and add credits in ppv credits record
// nano 80 : set provider bitmap package
// nano 82 : signature
// nano 87 : set provider data for ins 44
// nano 90 : write primary key
// nano 91 : write secondary key
// nano B0 : store seca record of a given type
// nano D0 : change provider name
// nano F0 : verify CUSTWP
if (nano==0x17 && !TestOnly){
// Grib - Region code update
// addr=getProvAddr(p1) + EE_ENT_REGION;
// Store the region code.
ee_write(addr + EE_ENT_REGION,aux1);
} else
if (nano==0x21){
// Check to see if we are just checking out the EMM instruction
if (TestOnly){
if (!cardHasExpired(p1,idx,TRUE)){
sw2=0x09;
return 0;
}
} else {
// update expiration date
//addr=getProvAddr(p1) + EE_ENT_SUBS_DATE;
ee_updateString(addr + EE_ENT_SUBS_DATE,&buffer[idx+1],2);
pnanos++;
}
} else
if (nano==0x22 && !TestOnly){
// test card expiration date
if (cardHasExpired(p1,idx,FALSE)){
sw1=0x93; sw2=0x01;
return 0;
}
} else
if (nano==0x41 && !TestOnly){
// update PPUA
//addr=getProvAddr(p1)+ EE_ENT_PPUA;
if (ee_updateString(addr + EE_ENT_PPUA,&buffer[idx+1],4)){
sw2 = 0x19; // 90 19
}
} else
// nano 80 : set provider bitmap package
if (nano==0x80 && TestOnly){
// update PBM 8 bytes
pnanos=0;
for(cnt=0; cnt<8; cnt++){
if (buffer[idx+1+cnt]){
pnanos++;
}
}
// If PBM is being reset then ignore packet
if (!pnanos){
sw2=0x09;
return 0;
}
} else
if (nano==0x90 || nano==0x91){
// update primary or secondary key
if (TestOnly){
if (TestKey(idx,p1,nano&0x01))
invalid_ECM=1;
} else {
updateKey(idx,p1,nano&0x01);
}
} else
if (nano==0xF0 && !TestOnly){
// CustWP-Bitmap
//u08 custwp;
//addr=getProvAddr(p1)+(EE_ENT_PPUA + 3);
//custwp = ee_read(addr+(EE_ENT_PPUA + 3));
// Should reuse vars like this but want the extra space
pnanos = ee_read(addr+(EE_ENT_PPUA + 3));
if (!isCustWPActive(idx, pnanos)){ // if (!isCustWPActive(idx, custwp)){
// If this assets and are not different from zero -> 90 09
cnt = 0x00;
//custwp = 0xff;
pnanos = 0xff;
do{
cnt++;
if (isCustWPActive(idx,cnt)){
// Found an Active CustWP! Updating Ppua!
ee_write(addr+(EE_ENT_PPUA + 3),cnt);
// it ignites red LED, was extinguished in proxima 0x3c
RED_INFO_LED_ON;
//custwp=cnt;
pnanos=cnt;
}
} while (cnt!=pnanos); //(cnt!=custwp);
}
} // end of nano f0
} // end of EMM nanos
// next nano
nano>>=4;
if (nano>0xC) nano=(nano-0x0b)<<3;
idx+=(nano+1);
}
}
// Combined the sign prepares from 38, 3c and 40 Instructions
// saves around 50 odd bytes :)
u08 PrepareSigCheck(u08 p1, u08 p2, u08 p3, u08 checkMK)
{
u08 tmp;
// 13-Apr-2002,
// If not super encrypted then need to check a signature is supplied first!
if (!(p2&0x80)){
// Not encrypted, check signature presence
if (!signaturePresent(p3)){
sw2=0x02;
goto PrepFailed;
}
}
// 17-Apr-2002, to verify that it uses MK
if (checkMK && (p2&0x0f)>0x0b){
sw2=0x13;
goto PrepFailed;
}
// it verifies existence of keys
tmp = keyExist(p1, p2&0x0f);
if (tmp==0x00){
// It does not exist key primary 90 1D
sw2=0x1D;
goto PrepFailed;
} else
if (tmp==0x50 && (p1&0x10)){
// It does not exist key secondary 90 1F
sw2=0x1F;
goto PrepFailed;
}
// decrypt buffer before continueing
getKey(p1,p2);
decode(p2,p3);
// Return 0 for OK... caller will jmp to TX_Data on anything else
return 0;
PrepFailed:
return 1;
}
// Secoms construction of 06 record returns.... how complicated!
// Append Key Index and trailer for Primary\Secondary keys
u08 *ConstructKeyRegistry(u08 tipo,u08 Prov,u08 *lista){
if ((tipo&0xf0)==0xf0){ // Si tenemos la primaria y secundaria
*lista++=tipo;
*lista++=0x80|Prov;
*lista++=0x50|(tipo&0x0f);
*lista++=0xc0|Prov;
} else if ((tipo&0x50)==0x50) {// Si tenemos solo la primaria
*lista++=tipo;
*lista++=0x80|Prov;
}
return lista;
}
// Build a list (using log buffer) of all the records on the card
void ConstructEEpromList(u08 ndrProviders){
// It is used to store the list, the table that contendra the instruction to do log (to save space)
// The list this structured of the following form:
// A registry is of two bytes reason why to correctly cross it habra that to jump of two in two
// The first field contains the type of registry and the second is the descriptive Byte
// Each registry of this table identifies to one virtual one in eeprom.
// The order of the registries is not accidental, this fact asi despues to analyze a pile of original cards
u08 *punt1=&log_buffer[2], ind1, ind2;
// REGISTRIES RECORDS
*punt1++=0x01; // First type of record STARTUP
*punt1++=0xe0;
*punt1++=0; // Second type of record PPV
*punt1++=0xe0;
punt1=ConstructKeyRegistry(keyExist(0,0),0,punt1); // Registries of mks 00
*punt1++=0x02; // Date of Activation of card
*punt1++=0xe0;
// Extract the PBM and Keys for all the providers
for (ind1=0;ind1<=ndrProviders;ind1++){
// PBM of the supplier, single if it is not empty
if (ind1){
*punt1++=0;
*punt1++=0x90|ind1;
}
// Loop through for current provider build list of keys in use!
for (ind2=(ind1)?0:1;ind2<16;ind2++){
punt1=ConstructKeyRegistry((keyExist(ind1,ind2)|ind2),ind1,punt1);
}
/* For the moment don`t want to support the PPV returns :)
if (ind1) { // Registries PPV, Single if not empty
*punt1++=0x0; // Registry of Credit PPV of the Supplier
*punt1++=0xd0|ind1;
*punt1++=0x0; // A registry of Event PPV anyone
*punt1++=0xb0|ind1;
}
*/
}
*++punt1=0xff; // End of list
}
// End of Secom 06 record construction!
// info en KeyLeds
void LED_Display(void)
{
// keyleds:
// - 0: always off (low power supply decos) (PIN:9999)
// - 1: show operation key in use (PIN:9998)
// - 2: show current provider index (PIN:9997)
u08 keyleds = 0x00;
keyleds = ee_read(EE_KEYLEDS + Extra_Funcard_Space);
if (keyleds==0){
outp(0x0F,PORTD);
} else if (keyleds==1){
outp(~(currentKey),PORTD);
} else if (keyleds==2){
outp(~(currentProvider),PORTD);
}
}
int main(void)
{
u08 *ptrAux; // Pointer used by secom code
u16 addr_prov; // Store the address of the current provider
u08 inst=0,p1=0,p2=0,p3=0;
u08 numProviders;
// Don`t really need a dedicate var for this
//u08 cla=0;
u08 lastprovider=0;
u08 ind=0;
u08 aux1=0;
u08 aux2=0;
// Number of complete registry inst 32 interations
u08 RegActual=0;
// Desactiva el comparador analogico :P
sbi(ACSR,7);
// Configura Puertos B y D
// El puerto B :
// - leds de colores (pins 2,3,4)
// - i/o (pin 6)
outp(0x1C,DDRB); // 0b00011100
outp(0x1C,PORTB); // 0b01011100
// El puerto D :
// - KeyLeds (pins 0,1,2,3)
outp(0x0F,DDRD); // 0b00001111
outp(0x0F,PORTD); // 0b00001111
// init eeprom externa
/*-----------------------------------------------------------------------------
| Detección modo Apollo:
|
| The state of bit 7 is verified and bit 5 of port B. If the 7 are to 0 and
| the 5 to 1, somebody to them has changed (FunStudio) - > Apollo way
|
+------------------------------------------------------------------------------------*/
if(0x80 == (inp(PINB) & 0xA0))
{
sbi(DDRB,6);
sbi(PORTB,6);
RED_INFO_LED_ON;
ptrSend = &SendA;
ptrReceive = &ReceiveA;
cbi(PORTB,6);
}
else
{
// Modo Phoenix
ptrSend = &Send;
ptrReceive = &Receive;
// Enviamos ATR
ORANGE_INFO_LED_ON;
sendString(ATR,16);
ORANGE_INFO_LED_OFF;
// Send(0x90);
// Send(0x00);
}
extee_init();
// Populate the offset value depending on the type of eeprom we have in use.
ee_SetEEPromSize();
// Load the number of providers from the eeprom
numProviders = ee_read(EE_NUM_ENTETIES) - 1;
// Now loading OldStyle PPV setting from ext eeprom config
OldStylePPV = !ee_read(EE_FULLAUTO);
// Load the log style they want to use
LOG_Method = ee_read(EE_LOGMETHOD);
// Load up the number of providers to return when asked
ProviderCount = ee_read(EE_PROVIDER_CNT);
// Put an upper limit on the provider count to stop
// users setting to higher than available!
if (ProviderCount>numProviders){ProviderCount=numProviders + 1;}
// For the decos without PIN It allows to block channels X
decodeX = (ee_read(EE_FLAGS) & FLG_BLOQUEAR_TX);
#ifdef MODO_LOG
// Is AutoLog enabled?... hate it myself but.....
modo_log = ee_read(EE_FLAGS) & FLG_AUTOLOG;
// Set the start point in the ee_ to start the log
leer_config_log(numProviders);
#endif
while (1){
// Decrement the command counter (bad PPV enent cache)
if (CommandCountDown){CommandCountDown--;}
// status word by default
sw1=0x90;
sw2=0x00;
GREEN_INFO_LED_OFF; // 'busy' led
// Using a temp var for class... no need to retain
ind=(*ptrReceive)(); // C1 en SECA
GREEN_INFO_LED_ON; // 'busy' led
inst=(*ptrReceive)(); // Instruction
p1=(*ptrReceive)(); // parameter 1
p2=(*ptrReceive)(); // parameter 2
p3=(*ptrReceive)(); // Length of command
// Check class in temp var
if (ind!=0xC1){
// Class not supported: 6E 00
//lastInst=0;
sw1=0x6E;
goto TX_Data;
}
if (inst&1){
// The first bit of inst must be zero
sw1=0x6D;
lastInst=0;
goto TX_Date_MPSkip;
}
if ((!p3 && inst&2) || p3>MAX_COMMAND_LENGHT){
// Length of incorrect entrance: 67 00
sw1=0x67;
lastInst=0;
// Do not send back data for invalid length
p3=0;
goto TX_Date_MPSkip;
}
// Check p3, we do not send an ack for anything without length!
if (p3)
// Return ACK
(*ptrSend)(inst);
if (inst&2){
// CARD->CAM
fillBuffer(0,MAX_COMMAND_LENGHT,0xFF);
} else {
// CAM->CARD
if (p3)
receiveString(p3);
#ifdef MODO_LOG
// alvamos the buffer for log
_memcpy(&log_buffer[5],buffer,p3);
#endif
}
/*-----------------------------------------------------------------------------
| In principle, treating this possibility does not have here to produce problems
| With !support_phoenix we made sure to be able to send all the directions
| it stops INS 20 y 22
+-----------------------------------------------------------------------------*/
// Check provider index, not applicable to serial request.
if (((p1 & 0x0F) > numProviders && inst!=0x0e) && (!support_phoenix)){
// supported supplier not 90 04
sw2=0x04;
goto TX_Data;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// INSTRUCTION 0x34: Specification of the Request of Data
if (inst==0x34){
// Sólo soportamos dos peticiones:
// 00 00 00 : Provider Package Bitmap Records
// 04 00 01 : SECA Startup Records
// The request is stored in Comando34
// Check that provider is within the limit
if ((p1&0x0F)>ProviderCount){
// Need to validate supplier index
sw2=0x04;
goto TX_Data;
}
if (p3!=3){
// Incorrect length of the entrance: 67 00
sw1=0x67;
goto TX_Data;
}
_memcpy(Comando34,buffer,3);
//lastInst=inst;
} else
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// INSTRUCTION 0x32: Request of Data
// INSTRUCTION 0x36: As per 0x32 but with additional options
// 2Fh=d4 30h=d5 87-8Eh=a1..a8
if (inst==0x32 || inst==0x36){
/*
; Ins 32 : output data requested
; data from ins 34 d1 = 29h d2 = 2Dh d3 = 2Eh
; d1 d2 d3
; 0 0 0 Provider package bitmap record C1 32 xx 00 0A 83 data 04
; 1 0 0 Provider PPV credits record C1 32 xx 00 0A 84 data 04
' 2 ....... a check on something??
; 3 x x Provider PPV event record C1 32 xx 00 0D B1 data 04
; 4 0 x Seca record C1 32 00 00 0D B1 data 04
; 6 x x Given record (number) C1 32 xx 00 12 D2 data 03
*/
// Store the command 34 stuff into vars, takes a little less
// space than references in the code
ind = Comando34[0];
aux1 = Comando34[1];
aux2 = Comando34[2];
if (p2){
// incorrect value of p2 (p2!=0) 94 02
sw1=0x94;
sw2=0x02;
goto TX_Data;
// Check last instruction was a 36 or 38
} else if (lastInst!=inst && lastInst!=0x38 && lastInst!=0x34){
sw2=0x14;
goto TX_Data;
} else if (inst==0x36){
// ins 36 error in parameter P1
if (lastprovider!=p1){
sw1=0x94; sw2=0x01;
goto TX_Data;
}
} else {
// Works on a MOSC but not documented...
if (ind==0x02 && (lastprovider)){
sw2=0x15;
goto TX_Data;
}
}
// Default for returned records is 0x04
buffer[0]=0x04;
// Command 00 - - - - - - - - - - - - - - - - - - - -
if (ind==0x00){
// Command 00
// Data: 00 00 -> Provider Package Bitmap Records
if (p3<0x0A){
// It does not fit, to send 0x03
buffer[0]=0x03;
} else if (p1){
// ok, all except SECA
buffer[0]=0x83;
ee_readString(buffer + 1, getProvAddr(p1) + EE_ENT_PBM, 8);
buffer[0x0A-1]=0x04;
}
} else if (ind==0x01){
if (p3<0x0A){
// It does not fit, to send 0x03
buffer[0]=0x03;
}
} else if (ind==0x03){
// Command 03
// Data: xx xx -> Provider PPV Records (xx xx = EventID)
if(p3<0x0e){
buffer[0] = 0x03;
} else {
// buffer[0]=0x04;
if (EventInCache(aux1, aux2) || CommandCountDown || p3!=0x20){
// Bad record
AddPPVEvent(aux1,aux2);
IncrementECMCount(inst);
} else {
// Store last PPV request, need to check the 31 nano in 3c
// to ensure they match
// Hoping for an auto purchase
//if (OldStylePPV || CapturePPVEvent>1 || EventUpdatedin3C){// || (ppv_record[EVENT_ID1]==Comando34[1] && ppv_record[EVENT_ID2]==Comando34[2])){
//if ((OldStylePPV || EventUpdatedin3C) && (ppv_request[0]==aux1 && ppv_request[0]==aux2)){
needPin = FALSE;
if (OldStylePPV || EventUpdatedin3C){
// needPin = FALSE;
ppv_record[EVENT_ID1] = aux1;
ppv_record[EVENT_ID2] = aux2;
// Return the BX record requested
_memcpy(buffer,ppv_record,14);
EventUpdatedin3C = FALSE;
} else {
EventUpdatedin3C=TRUE;
}
}
}
} else if (ind==0x04){
// Data: 00 00 -> SECA PPV Records
// 00 01 -> SECA Startup Records
// 00 02 -> SECA Records de Activación
// This one will not get caught by main increment
IncrementECMCount(inst);
// 12-Apr-2002, we have move the size check outside
// the check on record number
if (p3<0x0d){
// Not enough space for result! 0x03
buffer[0]=0x03;
// SECA Startup Records
} else {
// Only information on Seca p1=0 can be requested
if (aux2<=0x02 && !p1){
// Build the output record
buffer[0]=0xb2;
if (aux2==0x00){
ee_readString(buffer + 1, EE_SECA_PPVSTARTUP, 11);
} else {
if (aux2==0x01){
ee_readString(buffer + 1, EE_STARTUP_STR, 11);
} else {
ee_readString(buffer + 1, EE_SECA_ACTIVATE, 11);
}
}
buffer[0x0D-1]=0x04;
}
}
} else if (ind==0x06){
// If it is the first request to initialize the registry
// to the first item to send
if (lastInst==0x34) RegActual=aux2;
// We constructed the Virtual List of eeprom records (only need
// to build upto the current provider each time - required for
// record position information :()
ConstructEEpromList(p1);
// We initialized leader of construction of answer
aux2=0;
// Loop for construction of answer
while (1) {
// Memorizamos type of registry (RegActual*2)
ind = log_buffer[RegActual<<1];
// Description Memorizamos of Registry
aux1= log_buffer[(RegActual<<1)+1];
// If to the registries or the Supplier of the present
// Registry finished it is greater than the requested supplier
if ((aux1==0xff)||((aux1&0x0f)>(p1&0x0f))){
buffer[aux2]=0x04;
goto TX_Data;
}
// If the Supplier of the Present Registry is minor who the asked for supplier
if ((aux1&0x0f)<(p1&0x0f)){
RegActual++; // We increased I number of registry
continue; // We return to verify
}
// If the following registry does not fit in the answer message
if ((aux2+18)>p3){
buffer[aux2]=0x03;
goto TX_Data;
}
// First part of the answer
buffer[aux2] = 0xd2;
buffer[aux2+1]= 0;
buffer[aux2+2]= RegActual;
// We initialized this part of the answer to 0
fillBuffer(aux2+12,aux2+17,0x00);
// We assigned leader for saving of space
ptrAux = &buffer[aux2+3];
addr_prov = getProvAddr(p1);
// Following Part of the Answer depending on the type of registry to send
// SECA - PPV
if ((ind==0x00)&&(p1==0)) {
ee_readString(ptrAux, EE_SECA_PPVSTARTUP, 11);
// SECA - Start-up
} else if (ind==0x01) {
// We read startup record of eeprom
ee_readString(ptrAux, EE_STARTUP_STR, 11);
// SECA - Registry of activation of the card
} else if (ind==0x02) {
ee_readString(ptrAux, EE_SECA_ACTIVATE, 11);
// Registry of suppliers - Package BitMap (PBM)
} else if (((aux1&0xf0)==0x90)&&(p1)) {
*ptrAux=0x00;
// We read PBM of the supplier
ee_readString(&buffer[aux2+4],addr_prov + EE_ENT_PBM ,8);
// Registry of suppliers - Key
} else if (((ind&0xf0)==0xf0)||((ind&0xf0)==0x50)) {
*ptrAux=ind;
if (!currentKey){
addr_prov = getPKAddr(p1,ind&0x0f);
addr_prov = ((aux1&0xf0)==0xC0)?addr_prov+(16*8):addr_prov;
//if ((aux1&0xf0)==0xC0){addr_prov=addr_prov+8;}
// If no key in use then populate the key details too
ee_readString(&buffer[aux2+4],addr_prov,8);
}
/* For the moment don`t want to support the PPV returns :)
// Registry of suppliers - Credit PPV
} else if ((aux1&0xf0)==0xd0) {
// We initialized answer with 0x00
fillBuffer(aux2+3,aux2+13,0x00);
// PPV Credit handler not available in GoM!
//buffer[aux2+7]=fichasppv;
//buffer[aux2+8]=FechaRec[0];
//buffer[aux2+9]=FechaRec[1]-1;
// Registry of Suppliers - a Registry of Event PPV anyone
} else if ((aux1&0xf0)==0xb0) {
ee_readString(ptrAux, EE_SECA_PPVSTARTUP, 11);
// So that the events are not always equal
// PPV Credit handler not available in GoM!
//buffer[aux2+4]=FechaRec[0];
*/
}
buffer[aux2+14]=aux1; // Descriptive byte
aux2+=17; // We increased leader of construction of message in 1 registry
RegActual++; // We increased I number of registry by which we go
}
} else {
// A invalid record request always returns 0x03....
buffer[0]=0x03;
}
} else
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// INSTRUCTION 0x0E: Serial number of the card
if (inst==0x0E){
fillBuffer(0,2,0x00);
// I number of series this in SECA.UA
ee_readString(buffer + 2, EE_NUM_TARJETA, 6);
// Turn off the pheonix interface when the serial is requested
support_phoenix=0x00;
} else
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// INSTRUCTION 0x16: Enumeration of Suppliers
if (inst==0x16){
fillBuffer(0,6,0x00);
if (currentKey){
// This is for the euro boys :p
aux1=ProviderCount;
// This one will not get caught by main increment
IncrementECMCount(inst);
} else {
aux1=numProviders + 1; //number of suppliers + seca
}
buffer[2]=rightShift(0xff,16-aux1);
buffer[3]=rightShift(0xff,(aux1<8?(8-aux1):0));
} else
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// INSTRUCTION 0x12: ProviderID (Ident)
if (inst==0x12){
// Dont want to include this in the history!
setupInfo(p1,p3);
} else
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// INSTRUCTION 0x3C: ECM ControlWords encrypted
if (inst==0x3C){
// p1 = provider number & pk-sk
// p2 = key index & superencription
// AntiECM - need to clear CW incase 3c fails
//_memcpy(CW,version+(16),16);
needPin = TRUE;
pinChecked = FALSE;
currentKey=p2&0x0F;
// Grib, moved sigcheck prep to sub
if (PrepareSigCheck(p1,p2,p3,FALSE)){
goto TX_Data;
}
// Do the LED display if necessary
LED_Display();
if (signatureCheck(p1,p3)){
RED_INFO_LED_OFF;
processNanos(p1,kECM,FALSE);
// Store the current provider... if the key
// in use is a normal operational one
if (currentKey==0x0c || currentKey==0x0d){
currentProvider=p1&0x0F;
/*
if (currentProvider!=lLastProvider){
lLastProvider=currentProvider;
// Re-capture PPV events for this new provider
CommandCountDown=60;
}
*/
}
} else {
// 90 02: Signature fails
sw2=02;
RED_INFO_LED_ON;
}
} else
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// INSTRUCTION 0x3A: ECM ControlWords decrypted
if (inst==0x3A){
// Invalid command sequence
if (lastInst!=0x3C){
sw2=0x14;
goto TX_Data;
}
// enviar CW desencriptadas
_memcpy(buffer,CW,16);
// Clear the Provider info flag
ECM_LastProviderChecked=0x00;
} else
// INSTRUCTION 0x30: Transactions protected by PIN
if (inst==0x30){
/*
; C1 30 00 00 10 (old pin)(new pin) : insert/modify pin
; C1 30 00 01 09 (pin)(protection status 0/1) : modify pin protection status
; C1 30 00 02 09 (pin)(flags) : modify flags (6 bit)
; bit 0 - addressable bit 01 (20.1 not used)
; bit 1 - addressable bit 06 (20.6 override parental control protection)
; bit 2 - addressable bit 07 (20.7 ppv management)
; bit 3 - addressable bit 03 (20.3 ppv special management)
; bit 6 - addressable bit 00 (20.0 ppv management)
; bit 7 - addressable bit 08 (21.0 instruction protected flag)
;-------------------------------------------------------------------------------
*/
if (p1!=0x00 || p2>0x02){
sw2=0x10; // Invalid pin number.....
goto TX_Data;
} else if ((p2==0x00 && p3!=0x10) || ((p2==0x01 || p2==0x02) && p3!=0x09)){
// There is an incorrect len check on PIN change
sw1=0x67;
goto TX_Data;
}
/*
// Introduccion/modificacion de PIN
// - El PIN se almacena en eeprom externa.
// - Utilizo los dos ultimos bytes de la UA
// del proveedor con indice 1 (sigue a SECA).
if (buffer[14]==0x27){
// Apagar Keyleds?
if (buffer[15]==0x0f){
ee_write(EE_KEYLEDS + Extra_Funcard_Space,0);
}
// Keyleds muestran indice de la clave en uso
if (buffer[15]==0x0e){
ee_write(EE_KEYLEDS + Extra_Funcard_Space,1);
}
// Keyleds muestran indice del proveedor actual
if (buffer[15]==0x0d){
ee_write(EE_KEYLEDS + Extra_Funcard_Space,2);
}
} else
//if ((buffer[14]==PIN_INFO_H) && (buffer[15]==PIN_INFO_L))
//infoMode=!(infoMode);
*/
#ifdef MODO_LOG
// No need to supply provider anymore, reuses first call
// tratar_PINS_log( buffer[14], buffer[15], numProviders );
tratar_PINS_log(buffer[14], buffer[15]);
#endif
/*-----------------------------------------------------------------------------
| Bloqueo de taquillas oficial:
| Una vez que se bloquea una taquiila, el deco pedirá PIN a la hora de la
| compra aún cuando esa taquilla no esté bloqueada. En una taquilla bloqueada,
| lo pide 2 veces: a la hora de entrar en la taquilla y a la hora de la compra.
|
| Lo que intentamos es simular el bloqueo de taquillas evitando la petición del
| PIN, a la hora de la compra, si esa taquilla no está bloqueada. En una bloqueada
| lo seguirá pidiendo 2 veces.
|
| A la hora de realizar la compra o volver a una taquilla ya comprada, el deco no
| nos da datos suficientes para poder saber en que situación estamos. El sistema
| que hemos adoptado garantiza, al menos, una petición de PIN cuando se entre en
| una taquilla bloqueada, ya sea para el proceso de compra o si cambiamos a una
| taquilla bloqueada con un evento de compra ya activado. En contra partida, en alguna
| situación, puede darse el caso de que se pida PIN en el proceso de compra de una
| taquilla sin bloquear :-)
|
| Variables que controlan la situación:
| needPin : Se activa al inicio, en cada INS 3C, si se introduce in PIN correcto
| o si en la comprobación del PIN se encontraba sin activar needPIN o
| pinChecked.
| Se desactiva con la INS 32, comando 4 (compra PPV)
|
| pinChecked : Se activa si se introduce un PIN correcto o si en la comprobación
| del PIN se encontraba sin activar needPIN o pinChecked.
| Se desactiva al inicio y en cada INS 3C.
|
| Se comprueba el PIN si cualquiera de las dos variables se encuentran
| activas en el momento de la petición del mismo.
+------------------------------------------------------------------------------------*/
if ((pinChecked) || (needPin)){
if (mem2eeprom_cmp(EE_PIN + Extra_Funcard_Space,&buffer[14],2)==0){
// ultimo PIN validado = PIN almacenado ?
if (mem2eeprom_cmp(EE_PIN + Extra_Funcard_Space,&buffer[6],2)==1){
// modificación del PIN
ee_writeString(EE_PIN + Extra_Funcard_Space,&buffer[14],2);
}
else {
sw2=0x10; // no validar PIN: 9010
}
} else {
needPin = pinChecked = TRUE;
}
} else { // Aunque parezca mentira
needPin = pinChecked = TRUE; // esta línea ocupa -2 bytes !!??
} // fin comprobación pin
} else
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// INSTRUCTION 0x02: give 8 bytes of data as result from IN THE 0x04
if (inst==0x02){
if (lastInst!=inst && lastInst!=0x04){
// Last instruction had to be a 0x04 ... return 9014
sw2=0x14;
goto TX_Data;
}
// Return the encoded 8 bytes
_memcpy(buffer,hash,8);
} else
// INSTRUCTION 0x04: Supply 8 bytes for encryption using 0x0f key
if (inst==0x04){
// Return result of 04 request to encrypt using 0f (in p2) key
if (p3!=8){
// Length of incorrect entrance: 67 00
sw1=0x67;
goto TX_Data;
}
if (p2!=0x0f){
// Requesting using key other than 0x0f ... return 9021
sw2=0x21;
goto TX_Data;
}
getKey(p1,p2);
// To prepare 16*0xff
encript(Key,buffer);
// Encode the contents of the buffer from 0 -> 7
_memcpy(hash,buffer,8);
} else
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// INSTRUCTION 0x48: set flags 20.2 and 20.5 ?
// INSTRUCTION 0x4A: associated 4c can be used but 4a retrieve still valid
// but returns just FF * p3
if (inst==0x48 || inst==0x4A){
// No action, just need to support the call
IncrementECMCount(inst);
} else
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// INSTRUCTION 0x4C: Puts down bitmap of the allowed IN THE 0x44-Nanos and Protection Flags
// INSTRUCTION 0x50: Add new provider...
// INSTRUCTION 0x54: LP Mode something...
// INSTRUCTION 0x56: LP Mode something...
if (inst==0x4c || inst==0x50 || inst==0x54 || inst==0x56){
// High or Low programming mode required.... therefore not available here!
// 90 11 Test-bit put not down, therefore instruction doesn't support
// but maybe 90 22 Card in the wrong mode ???
// maybe 9017 from the Rom dump????
sw2=0x11;
} else
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// INSTRUCTION 0x7c --------------------------------------------------------------
// result just taken from Secom (301)
if (inst==0x7c){
// Have no information on what this indicates.... not a return
// code in the SecaFAQ!
sw1=0x98; sw2=0x01;
} else
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// INSTRUCTION 0x42: Edition of the data from IN THE 0x44
// result just taken from Secom (301)
if (inst==0x42){
// 90 14: Gone ahead instruction wrong
sw2=0x14;
} else
// INSTRUCTION 0x38: Some bollocks to do with PPV
if (inst==0x38){
/*
; Ins 38 : data request and PPV event recording request
; C1 38 xx yy 1A 16 (d1) 2A (d2 d3) 2B (d4 d5) 86 (8 bytes) 82 (signature)
; Superencryption may be active
; on exit : 29h=d1 2Dh=d2 2Eh=d3 2Fh=d4 30h=d5 87-8Eh=(8 bytes for security)
; d1 d2 d3 as in ins 34 d4-d5 : PPV event spot
*/
// Grib, moved sigcheck prep to sub
if (PrepareSigCheck(p1,p2,p3,TRUE)){
goto TX_Data;
}
// Should check p1 for super encryption....
if (signatureCheck(p1,p3)==0){
// 90 02: Signature fails
sw2=0x02;
goto TX_Data;
}
// Store the copy security word in the 86 if supplied
if (buffer[p3-18]==0x86){
_memcpy(hash,&buffer[p3-17],8);
}
_memcpy(Comando34+1,buffer+1,1);
_memcpy(Comando34+2,buffer+3,2);
// Store d4 and d5 PPV Event ID too
_memcpy(Comando34+4,buffer+6,2);
} else
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// INSTRUCTION 0x40: EMM - pass to nano processing....
if (inst==0x40){
// Grib, moved sigcheck prep to sub
if (PrepareSigCheck(p1,p2,p3,TRUE)){
goto TX_Data;
}
// we ignored SECA ( C1 40 00 81 17 )
if (p1&0x0f){
if (signatureCheck(p1,p3)){
if (processNanos(p1,kEMM,TRUE)){
processNanos(p1,kEMM,FALSE);
} // PPUA does not exist
} else {sw2=0x02;}
}
} else
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// INSTRUCTION 0x1A: Reading of the Indices of keys
if (inst==0x1A){
// FF FF 0B 40 00
ee_readString(buffer, EE_AVAIL_KEYS, 5);
for (p2=0, aux1=5; p2<16; p2++){
ind=keyExist(p1,p2)|p2;
if (ind&0xf0){
// Nota: it considers space in SECA
//if(p1 | (p2 < 8)){
buffer[aux1++]=ind;
//}
}
}
} else
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// INSTRUCTION 0x5C: Lay down word to be encrypted
if (inst==0x5C){
if (p3!=0x08){
sw1=0x67;
}
} else
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// INSTRUCTION 0x5A: Lectura de claves encriptadas
if (inst==0x5A){
//lastInst=inst;
// Reading of encrypted keys
// Nota: it considers space in SECA
// aux1 = (p1 | (p2 < 8))? keyExist(p1,p2&0x0f) : 0x00;
aux1 = keyExist(p1,p2&0x0f);
if (aux1==0x00){
// It does not exist key primary 90 1D
sw2=0x1d;
goto TX_Data;
} else if (aux1==0x50 && (p1&0x10)){
// It does not exist key secondary 90 1F
sw2=0x1F;
goto TX_Data;
}
getKey(p1,p2);
// To prepare 8*0x00
fillBuffer(0,16,0x00);
encript(Key,buffer);
} else
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// INSTRUCTION 0x0A: System of Operation of the Card
if (inst==0x0A){
_memcpy(buffer,version,TOTAL_VERSION);
// Need to decrypt buffer + 39
// Decrypt the firmware result
antipurple(39,3);
} else
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// INSTRUCTION 0x22: Reading of eeprom
// C1 22 P1 P2 P3
// P1 Low Addr
// P2 High Addr
// P3 Bytes to read
if ( (inst==0x22) && support_phoenix){
ee_readString(buffer,(((u16)p1)<<8)+p2,p3);
} else
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// INSTRUCTION 0x20: writing of eeprom
// C1 20 P1 P2 P3
// P1 Low Addr
// P2 High Addr
// P3 Bytes to write
if ( (inst==0x20) && support_phoenix){
//RED_INFO_LED_ON;
ee_writeString((((u16)p1)<<8)+p2,buffer,p3);
//RED_INFO_LED_OFF;
} else {
// UNKNOWN INSTRUCTION
sw1=0x6D;
}
TX_Data:
// Check if the result was valid :)
lastInst=inst;
// Need for the associate 32/36 instruction, must be the same
// for some record requests
lastprovider = p1;
if (sw1!=0x90 || sw2){
IncrementECMCount(inst);
// Check if it exceeded visible provider count
if ((p1&0x0F)>=ProviderCount && inst!=0x40){
sw1=0x90; sw2=0x04;
if (inst&2){
// CARD->CAM
fillBuffer(0,MAX_COMMAND_LENGHT,0xFF);
}
}
if (inst!=0x3c || (sw1==0x90 && sw2==0x02)){
lastInst=0;
}
}
// Transmit without the hidden provider checks
TX_Date_MPSkip:
// Store the last command used global for the SetupInfo function...
if (inst!=0x12){LastNonProviderInst = inst;}
#ifdef MODO_LOG
if (modo_log && !support_phoenix){
// Log the current instruction to the eeprom
capturar_inst(0xc1,inst,p1,p2,p3);
}
#endif
// Grib - Bug fix :)
if(p3 && inst&2){
// CARD->CAM
sendString(buffer,p3);
}
(*ptrSend)(sw1);
(*ptrSend)(sw2);
/*
#ifdef MODO_LOG
if (ins_capturadas){
ORANGE_INFO_LED_ON;
}
#endif
*/
} // end of while(1){}
return 0;
} // end of main()
Bookmarks