emu 16
************************************************** ************************************************** **********************
//---------------------------------------------------------------------------
// st20cc -A -p c2 -filled emu16.s seca.s viac.s ******.s nagra.s nn_asm1.s st7.s -off binary
// st20cc -cpp -c2 -e do_ecm -rcu emu16.c seca2.c viac.c ******.c nagra.c nn_asm1.c st7.c -M map
// st20cc -c2 -e do_ecm -rcu emu16.s seca2.s viac.s ******.s nagra.s nn_asm1.s st7.s string.lib

#include "emu.h"
#include "seca.h"
#include "viac.h"
#include "******.h"
#include "nn.h"
#include "nagra_.h"

#include <string.h>
//---------------------------------------------------------------------------

/* 64 bytes used, adressing modulus 64 */
static byte tps_xor[] = {0x4F, 0xB4, 0xFC, 0x9B, 0x4A, 0x7F, 0x44, 0xFB,
0x05, 0xFF, 0xBD, 0xBB, 0x16, 0x2D, 0x6C, 0xC8,
0xD8, 0x96, 0xF9, 0xFE, 0x3F, 0xFF, 0x36, 0x24,
0xB6, 0xBF, 0x49, 0xC9, 0x2D, 0x36, 0x5E, 0xD0,
0x1F, 0x09, 0x7E, 0xA9, 0x7F, 0xFF, 0x64, 0xB6,
0x5B, 0x7E, 0xF8, 0xFC, 0x6E, 0x3F, 0x7F, 0xBF,
0xDD, 0x36, 0x12, 0xE9, 0x05, 0xFE, 0xB4, 0x6c,
0x6f, 0xfe, 0x7e, 0xc8, 0x25, 0x90, 0x6d, 0x90};
static byte multiv_xor[]={0x7E, 0x6D, 0x7E, 0x12, 0x76, 0xFD, 0x2F, 0xFE,
0x6D, 0xFE, 0xDA, 0x3F, 0xDA, 0x6D, 0xBD, 0x97,
0xD0, 0x6D, 0xD8, 0x9F, 0x69, 0xFD, 0xB6, 0x37,
0xFE, 0x7F, 0x36, 0x92, 0xBD, 0x52, 0x16, 0xDF,
0xFC, 0x96, 0xFF, 0x92, 0xFD, 0x6D, 0x7F, 0xB5,
0xFB, 0x4C, 0xB6, 0xB7, 0x7E, 0xD9, 0xFE, 0x9B,
0xFD, 0xF4, 0x6D, 0x9B, 0xB9, 0x36, 0xBF, 0x7F,
0xD2, 0x2D, 0xDF, 0xB7, 0xD9, 0xFE, 0x69, 0xBF};

//unsigned char nozapkey[]={0x81,0x7C,0xD1,0x1A,0x90,0x33,0xCB,0x58};
//unsigned char nozapkey[]={0x36,0x13,0xDF,0xA0,0x78,0x70,0x1C,0xA7};
static byte nozapkey[] = {
0x81,0x7C,0xD1,0x1A,0x90,0x33,0xCB,0x58,
0x36,0x13,0xDF,0xA0,0x78,0x70,0x1C,0xA7,
0x04,0x64,0x04,0x02,0x9A,0x1A,0x4E,0x6A,
0xF6,0x0B,0xFE,0xFA,0xC8,0xBF,0x49,0x3D,
0x96,0xB4,0xFB,0x73,0x07,0x29,0x37,0x20,
0x6D,0x21,0x87,0x53,0xF9,0x63,0x10,0xC6,
0x89,0xB1,0xF2,0x51,0x6D,0x1B,0x90,0xBA,
0x15,0x8D,0xD9,0x6B,0x08,0x93,0x4B,0x1E,
0x13,0x6B,0xC5,0xF0,0x13,0x44,0xE1,0x0A,
0x40,0xFC,0xF3,0x35,0x6B,0x0B,0x58,0x92,
0x0C,0xF4,0x3B,0xE1,0x8D,0x0A,0x87,0x64,
0xBA,0xB3,0x10,0xE8,0xC0,0x20,0xB8,0x07,
0x9A,0x8C,0xA9,0x10,0x65,0xFE,0x52,0xBE,
0x69,0xAE,0x45,0x2A,0x61,0xE7,0xB2,0x0E,
0xCA,0xB2,0x90,0xE0,0xB0,0x03,0x26,0xD2,
0xE8,0xBE,0x26,0x29,0x0C,0x58,0xF3,0x0E
};


int do_ecm(byte *ecm, byte *dw) {
byte ca_sys, *mask, *buf_emu;
int retval=0,i;
//byte reply[]={0,0x90,0,0,0x10};
__asm {
ld 0x40091364;
//ldnl 0;
ldnl 0;
ldnlp 0x263;
ldnl 0;
ldnl 0; // &BUF_EMU
stl buf_emu;
};

// reset result code
buf_emu[RESULT]=0;

// begin analyze
if((ecm[3]==0x81)&&(ecm[4]==0xFF)) return 3; //ca_sys=CRYPTO
if((ecm[8]==0x10)&&((ecm[9] & 0xF1)==0x01)) {
ca_sys=SECA;
goto chk_casys;
}//return 2; //ca_sys=SECA2

if((ecm[3]==0x70)&&(ecm[2]==(ecm[4]+2))) {
ca_sys=CONAX;
goto chk_casys;
}
if((ecm[3]==0xFF)&&(ecm[4]==0xFF)&&(ecm[5]==0xFF)) {
ca_sys=SKYCRYPT;
goto chk_casys;
}
if((ecm[8]==0x71)&&(ecm[ecm[2]-6]==0x82)) {
ca_sys=SECA;
goto chk_casys;
}
if((ecm[4]==0xD2)
&&(ecm[5]==0x01)
&&(ecm[6]==0x01)) { // TPS crypt
if(ecm[7]==0xDF) mask=tps_xor;
else mask=multiv_xor;
ecm[2] -= 5;
for (i=0;i<=ecm[2];i++)
ecm[4+i] = ecm[7+i]^mask[i & 0x3F];
//memcpy(ecm+4,tpsbuf,ecm[2]-4);
ca_sys=VIAC;
goto chk_casys;
}
if(((ecm[3]&0xA0)==0)
&&(ecm[4]==0x90)&&(ecm[5]==0x03)) {
ca_sys=VIAC;
goto chk_casys;
}
if(((ecm[3]==0x80)||(ecm[3]==0x03))
&&(ecm[2]==(ecm[4]+2))) {
ca_sys=NAGRA;
goto chk_casys;
}
// all other ecms assumed as ******
ca_sys=******;
chk_casys:
buf_emu[CA_SYS]=ca_sys;
switch (ca_sys)
{
case SECA:
buf_emu[KEYIDX]=ecm[7] & 0xF;
memcpy(buf_emu+IDENT,ecm+3,2);
retval=seca_ecm(ecm,dw,buf_emu);
break;
case VIAC:
//buf_emu[KEYIDX]=ecm[8] & 0xF;
memcpy(buf_emu+IDENT,ecm+6,3);
retval=viac_ecm(ecm,dw,buf_emu);
break;
case NAGRA:
buf_emu[KEYIDX]=(ecm[9] & 0x10) >> 4;
memcpy(buf_emu+IDENT,ecm+5,2);
retval=nagra_ecm(ecm,dw,buf_emu);
break;
case ******:
memset(buf_emu+IDENT,0,3);
buf_emu[IDENT]=ecm[8];
buf_emu[KEYIDX]=ecm[9];
retval=******_ecm(ecm,dw,buf_emu);
break;
case CONAX:
memset(buf_emu+IDENT,0,3);
buf_emu[KEYIDX]=ecm[6];
retval=conax_ecm(ecm,dw,buf_emu);
break;
case SKYCRYPT:
buf_emu[KEYIDX]=0;
memset(buf_emu+IDENT,0,3);
retval=sky_ecm(ecm,dw,nozapkey);
break;
}
if(retval) {
//memcpy(dw,reply,sizeof(reply));
//dw[0x15]=0x90;
//dw[0x16]=0;
buf_emu[RESULT]=1;
}
else if(ca_sys==SECA) retval=2;
return retval;
}

int do_emm(byte *emm, byte ca_sys)
{
byte *buf_emu;
__asm {
ld 0x40091364;
//ldnl 0;
ldnl 0;
ldnlp 0x263;
ldnl 0;
ldnl 0; // &BUF_EMU
stl buf_emu;
};

switch (ca_sys)
{
case SECA: return seca_emm(emm, buf_emu) ;
case VIAC: return viac_EMM(emm,buf_emu);
case ******: return ******_EMM(emm,buf_emu);
case NAGRA: return nagra_emm(emm,buf_emu);
default: return 0;
}
return 0;
}


int update_keys(byte *buf_emu,byte *newkey, byte provIdx, byte casys){
int j, key_end;
byte key_header[3];
byte *keys;
keys=buf_emu+OPKEY_OFFSET;
key_header[0]=casys; // ca system
key_header[1]=(byte)provIdx; /* num of provider */
key_header[2]=*newkey; /* index of key */
key_end= ((*(buf_emu+OPKEY_END))<<|(*(buf_emu+OPKEY_END+1));
/* search for old key place */
while (keys <(buf_emu+key_end))
{
j=0;
for (;j<3;j++)
{
if(*(keys+j) != key_header[j]) break;
}
if(j==3) break; /* key found */
keys += OPKEY_LEN;
}
if(keys < (buf_emu+key_end)){
for (j=1;j<9;j++)
{
if (*(keys+j+2)!=newkey[j])
{
memcpy(keys+3,newkey+1,; /* replace old key */
return 1;

}

}
return 0;
}
else {
if(keys>(buf_emu+OPKEY_END-OPKEY_LEN)) return 0; /* not enough space for new key */
memcpy(buf_emu+key_end+3,newkey+1,; /* add new key and it's header */
memcpy(buf_emu+key_end,key_header,3);
key_end += OPKEY_LEN; /* update last key offset */
*(buf_emu+OPKEY_END)=(byte)(key_end>>;
*(buf_emu+OPKEY_END+1)=(byte)(key_end);
return 1;
}

}

// locate key in emu buffer
// returns pointer to key if found
byte *getkey(int keyidx, int providx, byte *buf_emu, byte casys)
{
int j, key_end;
byte key_header[3];
byte *keys;
keys=buf_emu+OPKEY_OFFSET;
key_header[0]=casys;
key_header[1]=(byte)providx;
key_header[2]=(byte)keyidx; /* index of key */
key_end= ((*(buf_emu+OPKEY_END))<<|(*(buf_emu+OPKEY_END+1));
/* search for key place */
while (keys <(buf_emu+key_end))
{
j=0;
for (;j<3;j++)
{
if(*(keys+j) != key_header[j]) break;
}
if(j==3) break; /* key found */
keys += OPKEY_LEN;
}
if(keys <(buf_emu+key_end)) return keys+3;
return 0;
}

int conax_ecm(byte *ecm,byte *dw,byte *emu_buf) {
int keyIdx;
byte *e,*n;
if(!emu_buf[0x20A]) return 0; // send to card
keyIdx=ecm[6];
if(keyIdx==emu_buf[0xEF4]) {
e=emu_buf+0xEF6;
n=emu_buf+0xF76;
}
else if(keyIdx==emu_buf[0xEF5]) {
e=emu_buf+0xF36;
n=emu_buf+0xFB6;
}
else return 0; // key not found in emu
return(conax_decrypt(ecm+7,(int)ecm[4]-2,e,n,dw));
}

int sky_ecm(byte *ecm,byte *dw,byte *Key) {
unsigned char tempcw[24];
unsigned char key[8];
int i;

for (i=0;i<16;i++) {
memcpy(key,Key,;
doPC1(key);

memcpy(tempcw,ecm+3+ecm[2]-24,24);
des(key,DES_ECS2_DECRYPT,tempcw);
if((tempcw[0]!= 0xFF)||(tempcw[1]!= 0xFF)) {
Key +=8;
continue;
}
des(key,DES_ECS2_DECRYPT,tempcw+;
des(key,DES_ECS2_DECRYPT,tempcw+16);
if(!memcmp(tempcw+18, "\xFF\xFF\xFF\xFF\xFF\xFF" , 6))
{
memcpy(dw,tempcw+2,16);
return 1;
}
}
return 0;
}
************************************************** ************************************************** **********************
MN

#ifndef nnH
#define nnH
#endif
#ifndef _GLOBAL_H_
#define _GLOBAL_H_ 1

/* PROTOTYPES should be set to one if and only if the compiler supports
function argument prototyping.
The following makes PROTOTYPES default to 1 if it has not already been
defined as 0 with C compiler flags.
*/
#ifndef PROTOTYPES
#define PROTOTYPES 1
#endif

/* POINTER defines a generic pointer type */
typedef unsigned char *POINTER;

/* UINT2 defines a two byte word */
typedef unsigned short int UINT2;

/* UINT4 defines a four byte word */
typedef unsigned long int UINT4;

#ifndef NULL_PTR
#define NULL_PTR ((POINTER)0)
#endif

#ifndef UNUSED_ARG
#define UNUSED_ARG(x) x = *(&x);
#endif

/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
returns an empty list.
*/
#if PROTOTYPES
#define PROTO_LIST(list) list
#else
#define PROTO_LIST(list) ()
#endif

#endif /* end _GLOBAL_H_ */

/* RSA key lengths.
*/
#define MIN_RSA_MODULUS_BITS 508
#define MAX_RSA_MODULUS_BITS 720
#define MAX_RSA_MODULUS_LEN ((MAX_RSA_MODULUS_BITS + 7) /
#define MAX_RSA_PRIME_BITS ((MAX_RSA_MODULUS_BITS + 1) / 2)
#define MAX_RSA_PRIME_LEN ((MAX_RSA_PRIME_BITS + 7) /

/* Maximum lengths of encoded and encrypted content, as a function of
content length len. Also, inverse functions.
*/
#define ENCODED_CONTENT_LEN(len) (4*(len)/3 + 3)
#define ENCRYPTED_CONTENT_LEN(len) ENCODED_CONTENT_LEN ((len)+
#define DECODED_CONTENT_LEN(len) (3*(len)/4 + 1)
#define DECRYPTED_CONTENT_LEN(len) (DECODED_CONTENT_LEN (len) - 1)

/* Maximum lengths of signatures, encrypted keys, encrypted
signatures, and message digests.
*/
#define MAX_SIGNATURE_LEN MAX_RSA_MODULUS_LEN
#define MAX_PEM_SIGNATURE_LEN ENCODED_CONTENT_LEN (MAX_SIGNATURE_LEN)
#define MAX_ENCRYPTED_KEY_LEN MAX_RSA_MODULUS_LEN
#define MAX_PEM_ENCRYPTED_KEY_LEN ENCODED_CONTENT_LEN (MAX_ENCRYPTED_KEY_LEN)
#define MAX_PEM_ENCRYPTED_SIGNATURE_LEN \
ENCRYPTED_CONTENT_LEN (MAX_SIGNATURE_LEN)
#define MAX_DIGEST_LEN 16

/* NN.H - header file for NN.C
*/

/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
Inc., created 1991. All rights reserved.
*/

/* Type definitions.
*/
typedef UINT4 NN_DIGIT;
typedef UINT2 NN_HALF_DIGIT;

/* Constants.

Note: MAX_NN_DIGITS is long enough to hold any RSA modulus, plus
one more digit as required by R_GeneratePEMKeys (for n and phiN,
whose lengths must be even). All natural numbers have at most
MAX_NN_DIGITS digits, except for double-length intermediate values
in NN_Mult (t), NN_ModMult (t), NN_ModInv (w), and NN_Div (c).
*/
/* Length of digit in bits */
#define NN_DIGIT_BITS 32
#define NN_HALF_DIGIT_BITS 16
/* Length of digit in bytes */
#define NN_DIGIT_LEN (NN_DIGIT_BITS / /* 4 */
/* Maximum length in digits */
#define MAX_NN_DIGITS \
((MAX_RSA_MODULUS_LEN + NN_DIGIT_LEN - 1) / NN_DIGIT_LEN + 1)
/* Maximum digits */
#define MAX_NN_DIGIT 0xffffffff
#define MAX_NN_HALF_DIGIT 0xffff

/* Macros.
*/
#define LOW_HALF(x) ((x) & MAX_NN_HALF_DIGIT)
#define HIGH_HALF(x) (((x) >> NN_HALF_DIGIT_BITS) & MAX_NN_HALF_DIGIT)
#define TO_HIGH_HALF(x) (((NN_DIGIT)(x)) << NN_HALF_DIGIT_BITS)
#define DIGIT_MSB(x) (unsigned int)(((x) >> (NN_DIGIT_BITS - 1)) & 1)
#define DIGIT_2MSB(x) (unsigned int)(((x) >> (NN_DIGIT_BITS - 2)) & 3)

/* CONVERSIONS
NN_Decode (a, digits, b, len) Decodes character string b into a.
NN_Encode (a, len, b, digits) Encodes a into character string b.

ASSIGNMENTS
NN_Assign (a, b, digits) Assigns a = b.
NN_ASSIGN_DIGIT (a, b, digits) Assigns a = b, where b is a digit.
NN_AssignZero (a, b, digits) Assigns a = 0.
NN_Assign2Exp (a, b, digits) Assigns a = 2^b.

ARITHMETIC OPERATIONS
NN_Add (a, b, c, digits) Computes a = b + c.
NN_Sub (a, b, c, digits) Computes a = b - c.
NN_Mult (a, b, c, digits) Computes a = b * c.
NN_LShift (a, b, c, digits) Computes a = b * 2^c.
NN_RShift (a, b, c, digits) Computes a = b / 2^c.
NN_Div (a, b, c, cDigits, d, dDigits) Computes a = c div d and b = c mod d.

NUMBER THEORY
NN_Mod (a, b, bDigits, c, cDigits) Computes a = b mod c.
NN_ModMult (a, b, c, d, digits) Computes a = b * c mod d.
NN_ModExp (a, b, c, cDigits, d, dDigits) Computes a = b^c mod d.
NN_ModInv (a, b, c, digits) Computes a = 1/b mod c.
NN_Gcd (a, b, c, digits) Computes a = gcd (b, c).

OTHER OPERATIONS
NN_EVEN (a, digits) Returns 1 iff a is even.
NN_Cmp (a, b, digits) Returns sign of a - b.
NN_EQUAL (a, digits) Returns 1 iff a = b.
NN_Zero (a, digits) Returns 1 iff a = 0.
NN_Digits (a, digits) Returns significant length of a in digits.
NN_Bits (a, digits) Returns significant length of a in bits.
*/
void NN_Decode PROTO_LIST
((NN_DIGIT *, unsigned int, unsigned char *, unsigned int));
void NN_Encode PROTO_LIST
((unsigned char *, unsigned int, NN_DIGIT *, unsigned int));
void NN_DecodeLE (NN_DIGIT *a,unsigned int digits, unsigned char *b,unsigned int len);

void NN_Assign PROTO_LIST ((NN_DIGIT *, NN_DIGIT *, unsigned int));
void NN_AssignZero PROTO_LIST ((NN_DIGIT *, unsigned int));
void NN_Assign2Exp PROTO_LIST ((NN_DIGIT *, unsigned int, unsigned int));

NN_DIGIT NN_Add PROTO_LIST
((NN_DIGIT *, NN_DIGIT *, NN_DIGIT *, unsigned int));
NN_DIGIT NN_Sub PROTO_LIST
((NN_DIGIT *, NN_DIGIT *, NN_DIGIT *, unsigned int));
void NN_Mult PROTO_LIST ((NN_DIGIT *, NN_DIGIT *, NN_DIGIT *, unsigned int));
void NN_Div PROTO_LIST
((NN_DIGIT *, NN_DIGIT *, NN_DIGIT *, unsigned int, NN_DIGIT *,
unsigned int));
NN_DIGIT NN_LShift PROTO_LIST
((NN_DIGIT *, NN_DIGIT *, unsigned int, unsigned int));
NN_DIGIT NN_RShift PROTO_LIST
((NN_DIGIT *, NN_DIGIT *, unsigned int, unsigned int));

void NN_Mod PROTO_LIST
((NN_DIGIT *, NN_DIGIT *, unsigned int, NN_DIGIT *, unsigned int));
void NN_ModMult PROTO_LIST
((NN_DIGIT *, NN_DIGIT *, NN_DIGIT *, NN_DIGIT *, unsigned int));
void NN_ModExp PROTO_LIST
((NN_DIGIT *, NN_DIGIT *, NN_DIGIT *, unsigned int, NN_DIGIT *,
unsigned int));
/*void NN_ModInv PROTO_LIST
((NN_DIGIT *, NN_DIGIT *, NN_DIGIT *, unsigned int));
void NN_Gcd PROTO_LIST ((NN_DIGIT *, NN_DIGIT *, NN_DIGIT *, unsigned int));
*/
int NN_Cmp PROTO_LIST ((NN_DIGIT *, NN_DIGIT *, unsigned int));
int NN_Zero PROTO_LIST ((NN_DIGIT *, unsigned int));

unsigned int NN_Bits PROTO_LIST ((NN_DIGIT *, unsigned int));
unsigned int NN_Digits PROTO_LIST ((NN_DIGIT *, unsigned int));

#define NN_ASSIGN_DIGIT(a, b, digits) {NN_AssignZero (a, digits); a[0] = b;}
#define NN_EQUAL(a, b, digits) (! NN_Cmp (a, b, digits))
#define NN_EVEN(a, digits) (((digits) == 0) || ! (a[0] & 1))
#define byte unsigned char
/*
NN_DIGIT NN_AddDigitMult PROTO_LIST
((NN_DIGIT *, NN_DIGIT *, NN_DIGIT, NN_DIGIT *, unsigned int));
NN_DIGIT NN_SubDigitMult PROTO_LIST
((NN_DIGIT *, NN_DIGIT *, NN_DIGIT, NN_DIGIT *, unsigned int));
*/

void R_memset (
POINTER output, /* output block */
int value, /* value */
unsigned int len); /* length of block */

int nagra_RSA(byte *in_msg,int keyselect,byte *n2,byte *n1,byte *e1, byte *decrypted);
void ParseECM(byte *buf, byte len, byte *plainwords) ;
int conax_decrypt(byte *buf, byte len, byte *e1, byte *n1, byte *plainwords);
void makeMECM(byte *primes, byte *MECM, int *idx);
void s2sse(byte *emm, byte *mod, byte *exp, byte *decrypted);
************************************************** ************************************************** **********************
mn_1
//---------------------------------------------------------------------------


//#pragma hdrstop

//#include "nn.h"

//---------------------------------------------------------------------------

//#pragma package(smart_init)
/* NN.C - natural numbers routines
*/

/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
Inc., created 1991. All rights reserved.
*/

//#include "global.h"
//#include "rsaref.h"
#include "nn.h"
//#include "digit.h"
//#include <mem.h>
#include <string.h>


int conax_decrypt(byte *buf, byte len, byte *e1, byte *n1, byte *plainwords){
unsigned char out[64];
int i, index,nDigits,eDigits;
const byte hash[] = {0x05, 0x00, 0x05};

NN_DIGIT N1[MAX_NN_DIGITS];
NN_DIGIT E1[MAX_NN_DIGITS];
NN_DIGIT ecm[MAX_NN_DIGITS], decm[MAX_NN_DIGITS];

NN_Decode(N1,MAX_NN_DIGITS,n1, 64);
NN_Decode(E1,MAX_NN_DIGITS,e1, 64);

/* begin RSA decrypt */
for (i=len;i>0 {
index = i-64; /* begin from last 64 bytes of ECM */
if(i-64 < 0)
index = 0;

NN_Decode(ecm,MAX_NN_DIGITS,buf+index,64);
nDigits = NN_Digits (ecm, MAX_NN_DIGITS);
eDigits = NN_Digits (E1, MAX_NN_DIGITS);
NN_ModExp(decm,ecm,E1,eDigits,N1,nDigits);
NN_Encode(out,64,decm,MAX_NN_DIGITS);
memcpy(buf+index, out, 64);

if(i%60 && index)
i-=i%60;
else
i-=64;

}
R_memset((POINTER)N1,0,sizeof(N1));
R_memset((POINTER)ecm,0,sizeof(ecm));
R_memset((POINTER)decm,0,sizeof(decm));
R_memset((POINTER)E1,0,sizeof(E1));
if(memcmp(hash, buf+2, 3) == 0 &&
memcmp(buf+5, buf+len-5, 5) == 0) {
/* Signature correct, parse decrypted packet */
ParseECM(buf+10,len-10,plainwords);
return 1;
} else
/* Signature incorrect */
return 0;

}
void ParseECM(byte *buf, byte len, byte *plainwords) {
int i;
for(i=0; i<len; ) {
byte nano = buf[i++];
byte nanolen = buf[i++];

switch(nano) {
case 0x80:
case 0x82:
/* mlogprint(dbg, "Nano 80 %02x - Provider %02x %02x\n", nanolen, buf[i+1], buf[i+2]);
curr_id = (buf[i+1]<<16)|(buf[i+2]<<; */
ParseECM(buf+i+3, nanolen-3, plainwords);
break;
case 0x81:
/* mlogprint(dbg, "Nano 81 %02x - Provider %02x %02x\n", nanolen, buf[i], buf[i+1]);*/
ParseECM(buf+i+2, nanolen-2, plainwords);
break;
case 0x30:
/* mlogprint(dbg, "Nano 30 %02x - Control words\n", nanolen);
curr_id &= ~0xff;
curr_id |= buf[i+1]; */
if(plainwords) {
memcpy(plainwords, buf+i+10, ;
memcpy(plainwords+8, buf+i+2, ;
}
break;

default:
break;
}
i += nanolen;
}
}


void R_memset (
POINTER output, /* output block */
int value, /* value */
unsigned int len) /* length of block */
{
if (len)
memset (output, value, len);
}

void R_memcpy (
POINTER output, /* output block */
POINTER input, /* input block */
unsigned int len) /* length of blocks */
{
if (len)
memcpy (output, input, len);
}

int R_memcmp (
POINTER firstBlock, /* first block */
POINTER secondBlock, /* second block */
unsigned int len) /* length of blocks */
{
if (len)
return (memcmp (firstBlock, secondBlock, len));
else
return (0);
}



/* Computes a = b * c, where b and c are digits.

Lengths: a[2].
*/



void NN_DigitMult (NN_DIGIT a[2],NN_DIGIT b,NN_DIGIT c)
{
NN_DIGIT t, u;
NN_HALF_DIGIT bHigh, bLow, cHigh, cLow;

bHigh = (NN_HALF_DIGIT)HIGH_HALF (b);
bLow = (NN_HALF_DIGIT)LOW_HALF (b);
cHigh = (NN_HALF_DIGIT)HIGH_HALF (c);
cLow = (NN_HALF_DIGIT)LOW_HALF (c);

a[0] = (NN_DIGIT)bLow * (NN_DIGIT)cLow;
t = (NN_DIGIT)bLow * (NN_DIGIT)cHigh;
u = (NN_DIGIT)bHigh * (NN_DIGIT)cLow;
a[1] = (NN_DIGIT)bHigh * (NN_DIGIT)cHigh;

if ((t += u) < u)
a[1] += TO_HIGH_HALF (1);
u = TO_HIGH_HALF (t);

if ((a[0] += u) < u)
a[1]++;
a[1] += HIGH_HALF (t);
}

/* Computes a = b - c*d, where c is a digit. Returns borrow.

Lengths: a[digits], b[digits], d[digits].
*/
static NN_DIGIT NN_SubDigitMult (NN_DIGIT *a, NN_DIGIT *b, NN_DIGIT c, NN_DIGIT *d,unsigned int digits)
{
NN_DIGIT borrow, t[2];
unsigned int i;

if (c == 0)
return (0);

borrow = 0;
for (i = 0; i < digits; i++) {
NN_DigitMult (t, c, d[i]);
if ((a[i] = b[i] - borrow) > (MAX_NN_DIGIT - borrow))
borrow = 1;
else
borrow = 0;
if ((a[i] -= t[0]) > (MAX_NN_DIGIT - t[0]))
borrow++;
borrow += t[1];
}

return (borrow);
}

/* Computes a = b + c*d, where c is a digit. Returns carry.

Lengths: a[digits], b[digits], d[digits].
*/
static NN_DIGIT NN_AddDigitMult (NN_DIGIT *a, NN_DIGIT *b, NN_DIGIT c, NN_DIGIT *d,unsigned int digits)
{
NN_DIGIT carry, t[2];
unsigned int i;

if (c == 0)
return (0);

carry = 0;
for (i = 0; i < digits; i++) {
NN_DigitMult (t, c, d[i]);
if ((a[i] = b[i] + carry) < carry)
carry = 1;
else
carry = 0;
if ((a[i] += t[0]) < t[0])
carry++;
carry += t[1];
}

return (carry);
}



/* Sets a = b / c, where a and c are digits.

Lengths: b[2].
Assumes b[1] < c and HIGH_HALF (c) > 0. For efficiency, c should be
normalized.
*/
void NN_DigitDiv (NN_DIGIT *a,NN_DIGIT b[2],NN_DIGIT c)
{
NN_DIGIT t[2], u, v;
NN_HALF_DIGIT aHigh, aLow, cHigh, cLow;

cHigh = (NN_HALF_DIGIT)HIGH_HALF (c);
cLow = (NN_HALF_DIGIT)LOW_HALF (c);

t[0] = b[0];
t[1] = b[1];

/* Underestimate high half of quotient and subtract.
*/
if (cHigh == MAX_NN_HALF_DIGIT)
aHigh = (NN_HALF_DIGIT)HIGH_HALF (t[1]);
else
aHigh = (NN_HALF_DIGIT)(t[1] / (cHigh + 1));
u = (NN_DIGIT)aHigh * (NN_DIGIT)cLow;
v = (NN_DIGIT)aHigh * (NN_DIGIT)cHigh;
if ((t[0] -= TO_HIGH_HALF (u)) > (MAX_NN_DIGIT - TO_HIGH_HALF (u)))
t[1]--;
t[1] -= HIGH_HALF (u);
t[1] -= v;

/* Correct estimate.
*/
while ((t[1] > cHigh) ||
((t[1] == cHigh) && (t[0] >= TO_HIGH_HALF (cLow)))) {
if ((t[0] -= TO_HIGH_HALF (cLow)) > MAX_NN_DIGIT - TO_HIGH_HALF (cLow))
t[1]--;
t[1] -= cHigh;
aHigh++;
}

/* Underestimate low half of quotient and subtract.
*/
if (cHigh == MAX_NN_HALF_DIGIT)
aLow = (NN_HALF_DIGIT)LOW_HALF (t[1]);
else
aLow =
(NN_HALF_DIGIT)((TO_HIGH_HALF (t[1]) + HIGH_HALF (t[0])) / (cHigh + 1));
u = (NN_DIGIT)aLow * (NN_DIGIT)cLow;
v = (NN_DIGIT)aLow * (NN_DIGIT)cHigh;
if ((t[0] -= u) > (MAX_NN_DIGIT - u))
t[1]--;
if ((t[0] -= TO_HIGH_HALF (v)) > (MAX_NN_DIGIT - TO_HIGH_HALF (v)))
t[1]--;
t[1] -= HIGH_HALF (v);

/* Correct estimate.
*/
while ((t[1] > 0) || ((t[1] == 0) && t[0] >= c)) {
if ((t[0] -= c) > (MAX_NN_DIGIT - c))
t[1]--;
aLow++;
}

*a = TO_HIGH_HALF (aHigh) + aLow;
}

static unsigned int NN_DigitBits PROTO_LIST ((NN_DIGIT));

/* Decodes character string b into a, where character string is ordered
from most to least significant.

Lengths: a[digits], b[len].
Assumes b[i] = 0 for i < len - digits * NN_DIGIT_LEN. (Otherwise most
significant bytes are truncated.)
*/
void NN_Decode (NN_DIGIT *a,unsigned int digits, unsigned char *b,unsigned int len)
{
NN_DIGIT t;
int j;
unsigned int i, u;

for (i = 0, j = len - 1; i < digits && j >= 0; i++) {
t = 0;
for (u = 0; j >= 0 && u < NN_DIGIT_BITS; j--, u +=
t |= ((NN_DIGIT)b[j]) << u;
a[i] = t;
}

for (; i < digits; i++)
a[i] = 0;
}

/* Decodes character string b into a, where character string is ordered
from least to most significant.

Lengths: a[digits], b[len].
Assumes b[i] = 0 for i < len - digits * NN_DIGIT_LEN. (Otherwise most
significant bytes are truncated.)
*/
void NN_DecodeLE (NN_DIGIT *a,unsigned int digits, unsigned char *b,unsigned int len)
{
NN_DIGIT t; // temporary long var for decoding chars
int j; /* index of char string */
unsigned int i, u; /* i - index in DIGIT's array, u - number of bit in t */

for (i = 0, j = 0; i < digits && j < len; i++) {
t = 0;
for (u = 0; j < len && u < NN_DIGIT_BITS; j++, u +=
t |= ((NN_DIGIT)b[j]) << u;
a[i] = t;
}

for (; i < digits; i++)
a[i] = 0; /* pad the rest of digit's array with 0 */
}

/* Encodes b into character string a, where character string is ordered
from most to least significant.

Lengths: a[len], b[digits].
Assumes NN_Bits (b, digits) <= 8 * len. (Otherwise most significant
digits are truncated.)
*/
void NN_Encode (unsigned char *a,unsigned int len, NN_DIGIT *b,unsigned int digits)
{
NN_DIGIT t;
int j;
unsigned int i, u;

for (i = 0, j = len - 1; i < digits && j >= 0; i++) {
t = b[i];
for (u = 0; j >= 0 && u < NN_DIGIT_BITS; j--, u +=
a[j] = (unsigned char)(t >> u);
}

for (; j >= 0; j--)
a[j] = 0;
}

void NN_EncodeLE (unsigned char *a,unsigned int len, NN_DIGIT *b,unsigned int digits)
{
NN_DIGIT t;
int j;
unsigned int i, u;

for (i = 0, j = 0; i < digits && j < len; i++) {
t = b[i];
for (u = 0; j < len && u < NN_DIGIT_BITS; j++, u +=
a[j] = (unsigned char)(t >> u);
}

for (; j < len; j++)
a[j] = 0;
}

/* Assigns a = b.

Lengths: a[digits], b[digits].
*/
void NN_Assign (NN_DIGIT *a,NN_DIGIT *b,unsigned int digits)
{
unsigned int i;

for (i = 0; i < digits; i++)
a[i] = b[i];
}

/* Assigns a = 0.

Lengths: a[digits].
*/
void NN_AssignZero (
NN_DIGIT *a,
unsigned int digits)
{
unsigned int i;

for (i = 0; i < digits; i++)
a[i] = 0;
}

/* Assigns a = 2^b.

Lengths: a[digits].
Requires b < digits * NN_DIGIT_BITS.
*/
void NN_Assign2Exp (
NN_DIGIT *a,
unsigned int b,unsigned int digits)
{
NN_AssignZero (a, digits);

if (b >= digits * NN_DIGIT_BITS)
return;

a[b / NN_DIGIT_BITS] = (NN_DIGIT)1 << (b % NN_DIGIT_BITS);
}

/* Computes a = b + c. Returns carry.

Lengths: a[digits], b[digits], c[digits].
*/
NN_DIGIT NN_Add (NN_DIGIT *a,NN_DIGIT *b,NN_DIGIT *c,unsigned int digits)
{
NN_DIGIT ai, carry;
unsigned int i;

carry = 0;

for (i = 0; i < digits; i++) {
if ((ai = b[i] + carry) < carry)
ai = c[i];
else if ((ai += c[i]) < c[i])
carry = 1;
else
carry = 0;
a[i] = ai;
}

return (carry);
}

/* Computes a = b - c. Returns borrow.

Lengths: a[digits], b[digits], c[digits].
*/
NN_DIGIT NN_Sub (NN_DIGIT *a,NN_DIGIT *b,NN_DIGIT *c,unsigned int digits)
{
NN_DIGIT ai, borrow;
unsigned int i;

borrow = 0;

for (i = 0; i < digits; i++) {
if ((ai = b[i] - borrow) > (MAX_NN_DIGIT - borrow))
ai = MAX_NN_DIGIT - c[i];
else if ((ai -= c[i]) > (MAX_NN_DIGIT - c[i]))
borrow = 1;
else
borrow = 0;
a[i] = ai;
}

return (borrow);
}

/* Computes a = b * c.

Lengths: a[2*digits], b[digits], c[digits].
Assumes digits < MAX_NN_DIGITS.
*/
void NN_Mult (NN_DIGIT *a,NN_DIGIT *b,NN_DIGIT *c,unsigned int digits)
{
NN_DIGIT t[2*MAX_NN_DIGITS];
unsigned int bDigits, cDigits, i;

NN_AssignZero (t, 2 * digits);

bDigits = NN_Digits (b, digits);
cDigits = NN_Digits (c, digits);

for (i = 0; i < bDigits; i++)
t[i+cDigits] += NN_AddDigitMult (&t[i], &t[i], b[i], c, cDigits);

NN_Assign (a, t, 2 * digits);

/* Zeroize potentially sensitive information.
*/
R_memset ((POINTER)t, 0, sizeof (t));
}

/* Computes a = b * 2^c (i.e., shifts left c bits), returning carry.

Lengths: a[digits], b[digits].
Requires c < NN_DIGIT_BITS.
*/
NN_DIGIT NN_LShift (NN_DIGIT *a,NN_DIGIT *b,unsigned int c,unsigned int digits)
{
NN_DIGIT bi, carry;
unsigned int i, t;

if (c >= NN_DIGIT_BITS)
return (0);

t = NN_DIGIT_BITS - c;

carry = 0;

for (i = 0; i < digits; i++) {
bi = b[i];
a[i] = (bi << c) | carry;
carry = c ? (bi >> t) : 0;
}

return (carry);
}

/* Computes a = c div 2^c (i.e., shifts right c bits), returning carry.

Lengths: a[digits], b[digits].
Requires: c < NN_DIGIT_BITS.
*/
NN_DIGIT NN_RShift (NN_DIGIT *a,NN_DIGIT *b,unsigned int c,unsigned int digits)
{
NN_DIGIT bi, carry;
int i;
unsigned int t;

if (c >= NN_DIGIT_BITS)
return (0);

t = NN_DIGIT_BITS - c;

carry = 0;

for (i = digits - 1; i >= 0; i--) {
bi = b[i];
a[i] = (bi >> c) | carry;
carry = c ? (bi << t) : 0;
}

return (carry);
}

/* Computes a = c div d and b = c mod d.

Lengths: a[cDigits], b[dDigits], c[cDigits], d[dDigits].
Assumes d > 0, cDigits < 2 * MAX_NN_DIGITS,
dDigits < MAX_NN_DIGITS.
*/
void NN_Div (NN_DIGIT *a, NN_DIGIT *b, NN_DIGIT *c,unsigned int cDigits, NN_DIGIT *d,unsigned int dDigits)
{
NN_DIGIT ai, cc[2*MAX_NN_DIGITS+1], dd[MAX_NN_DIGITS], t;
int i;
unsigned int ddDigits, shift;

ddDigits = NN_Digits (d, dDigits);
if (ddDigits == 0)
return;

/* Normalize operands.
*/
shift = NN_DIGIT_BITS - NN_DigitBits (d[ddDigits-1]);
NN_AssignZero (cc, ddDigits);
cc[cDigits] = NN_LShift (cc, c, shift, cDigits);
NN_LShift (dd, d, shift, ddDigits);
t = dd[ddDigits-1];

NN_AssignZero (a, cDigits);

for (i = cDigits-ddDigits; i >= 0; i--) {
/* Underestimate quotient digit and subtract.
*/
if (t == MAX_NN_DIGIT)
ai = cc[i+ddDigits];
else
NN_DigitDiv (&ai, &cc[i+ddDigits-1], t + 1); /* ai=cc[i+ddDigits-1]/(t + 1) */
cc[i+ddDigits] -= NN_SubDigitMult (&cc[i], &cc[i], ai, dd, ddDigits);

/* Correct estimate.
*/
while (cc[i+ddDigits] || (NN_Cmp (&cc[i], dd, ddDigits) >= 0)) {
ai++;
cc[i+ddDigits] -= NN_Sub (&cc[i], &cc[i], dd, ddDigits);
}

a[i] = ai;
}

/* Restore result.
*/
NN_AssignZero (b, dDigits);
NN_RShift (b, cc, shift, ddDigits); /* b = cc >> shift

/* Zeroize potentially sensitive information.
*/
R_memset ((POINTER)cc, 0, sizeof (cc));
R_memset ((POINTER)dd, 0, sizeof (dd));
}

/* Computes a = b mod c.

Lengths: a[cDigits], b[bDigits], c[cDigits].
Assumes c > 0, bDigits < 2 * MAX_NN_DIGITS, cDigits < MAX_NN_DIGITS.
*/
void NN_Mod (NN_DIGIT *a, NN_DIGIT *b,unsigned int bDigits, NN_DIGIT *c,unsigned int cDigits)
{
NN_DIGIT t[2 * MAX_NN_DIGITS], cc;
/* unsigned int ccDigits=NN_Digits(c,cDigits);
unsigned int bbDigits=NN_Digits(b,bDigits);
NN_Assign(t,b,bbDigits);
while (bbDigits>ccDigits)
{
cc=NN_Sub(t,t,c,ccDigits);
bbDigits=NN_Digits(t,bbDigits);
}
NN_Assign(a,t,bbDigits);
if(cc) a[bbDigits]=cc;
*/

NN_Div (t, a, b, bDigits, c, cDigits);


/* Zeroize potentially sensitive information.
*/
R_memset ((POINTER)t, 0, sizeof (t));
}

/* Computes a = b * c mod d.

Lengths: a[digits], b[digits], c[digits], d[digits].
Assumes d > 0, digits < MAX_NN_DIGITS.
*/
void NN_ModMult (NN_DIGIT *a, NN_DIGIT *b, NN_DIGIT *c, NN_DIGIT *d, unsigned int digits)
{
NN_DIGIT t[2*MAX_NN_DIGITS];

NN_Mult (t, b, c, digits);
NN_Mod (a, t, 2 * digits, d, digits);

/* Zeroize potentially sensitive information.
*/
R_memset ((POINTER)t, 0, sizeof (t));
}

/* Computes a = b^c mod d.

Lengths: a[dDigits], b[dDigits], c[cDigits], d[dDigits].
Assumes d > 0, cDigits > 0, dDigits < MAX_NN_DIGITS.
*/
void NN_ModExp (NN_DIGIT *a, NN_DIGIT *b, NN_DIGIT *c,unsigned int cDigits, NN_DIGIT *d,unsigned int dDigits)
{
NN_DIGIT bPower[3][MAX_NN_DIGITS], ci, t[MAX_NN_DIGITS];
int i;
unsigned int ciBits, j, s;

/* Store b, b^2 mod d, and b^3 mod d.
*/
NN_Assign (bPower[0], b, dDigits);
NN_ModMult (bPower[1], bPower[0], b, d, dDigits);
NN_ModMult (bPower[2], bPower[1], b, d, dDigits);

NN_ASSIGN_DIGIT (t, 1, dDigits);

cDigits = NN_Digits (c, cDigits);
for (i = cDigits - 1; i >= 0; i--) {
ci = c[i];
ciBits = NN_DIGIT_BITS;

/* Scan past leading zero bits of most significant digit.
*/
if (i == (int)(cDigits - 1)) {
while (! DIGIT_2MSB (ci)) {
ci <<= 2;
ciBits -= 2;
}
}

for (j = 0; j < ciBits; j += 2, ci <<= 2) {
/* Compute t = t^4 * b^s mod d, where s = two MSB's of ci.
*/
NN_ModMult (t, t, t, d, dDigits);
NN_ModMult (t, t, t, d, dDigits);
if ((s = DIGIT_2MSB (ci)) != 0)
NN_ModMult (t, t, bPower[s-1], d, dDigits);
}
}

NN_Assign (a, t, dDigits);

/* Zeroize potentially sensitive information.
*/
R_memset ((POINTER)bPower, 0, sizeof (bPower));
R_memset ((POINTER)t, 0, sizeof (t));
}

/* Compute a = 1/b mod c, assuming inverse exists.

Lengths: a[digits], b[digits], c[digits].
Assumes gcd (b, c) = 1, digits < MAX_NN_DIGITS.
*/
void NN_ModInv (NN_DIGIT *a, NN_DIGIT *b, NN_DIGIT *c,unsigned int digits)
{
NN_DIGIT q[MAX_NN_DIGITS], t1[MAX_NN_DIGITS], t3[MAX_NN_DIGITS],
u1[MAX_NN_DIGITS], u3[MAX_NN_DIGITS], v1[MAX_NN_DIGITS],
v3[MAX_NN_DIGITS], w[2*MAX_NN_DIGITS];
int u1Sign;

/* Apply extended Euclidean algorithm, modified to avoid negative
numbers.
*/
NN_ASSIGN_DIGIT (u1, 1, digits);
NN_AssignZero (v1, digits);
NN_Assign (u3, b, digits);
NN_Assign (v3, c, digits);
u1Sign = 1;

while (! NN_Zero (v3, digits)) {
NN_Div (q, t3, u3, digits, v3, digits);
NN_Mult (w, q, v1, digits);
NN_Add (t1, u1, w, digits);
NN_Assign (u1, v1, digits);
NN_Assign (v1, t1, digits);
NN_Assign (u3, v3, digits);
NN_Assign (v3, t3, digits);
u1Sign = -u1Sign;
}

/* Negate result if sign is negative.
*/
if (u1Sign < 0)
NN_Sub (a, c, u1, digits);
else
NN_Assign (a, u1, digits);

/* Zeroize potentially sensitive information.
*/
R_memset ((POINTER)q, 0, sizeof (q));
R_memset ((POINTER)t1, 0, sizeof (t1));
R_memset ((POINTER)t3, 0, sizeof (t3));
R_memset ((POINTER)u1, 0, sizeof (u1));
R_memset ((POINTER)u3, 0, sizeof (u3));
R_memset ((POINTER)v1, 0, sizeof (v1));
R_memset ((POINTER)v3, 0, sizeof (v3));
R_memset ((POINTER)w, 0, sizeof (w));
}

/* Computes a = gcd(b, c).

Lengths: a[digits], b[digits], c[digits].
Assumes b > c, digits < MAX_NN_DIGITS.
*/
void NN_Gcd (NN_DIGIT *a, NN_DIGIT *b, NN_DIGIT *c,unsigned int digits)
{
NN_DIGIT t[MAX_NN_DIGITS], u[MAX_NN_DIGITS], v[MAX_NN_DIGITS];

NN_Assign (u, b, digits);
NN_Assign (v, c, digits);

while (! NN_Zero (v, digits)) {
NN_Mod (t, u, digits, v, digits);
NN_Assign (u, v, digits);
NN_Assign (v, t, digits);
}

NN_Assign (a, u, digits);

/* Zeroize potentially sensitive information.
*/
R_memset ((POINTER)t, 0, sizeof (t));
R_memset ((POINTER)u, 0, sizeof (u));
R_memset ((POINTER)v, 0, sizeof (v));
}

/* Returns sign of a - b.

Lengths: a[digits], b[digits].
*/
int NN_Cmp (NN_DIGIT *a, NN_DIGIT *b,unsigned int digits)
{
int i;

for (i = digits - 1; i >= 0; i--) {
if (a[i] > b[i])
return (1);
if (a[i] < b[i])
return (-1);
}

return (0);
}

/* Returns nonzero iff a is zero.

Lengths: a[digits].
*/
int NN_Zero (NN_DIGIT *a, unsigned int digits)
{
unsigned int i;

for (i = 0; i < digits; i++)
if (a[i])
return (0);

return (1);
}

/* Returns the significant length of a in bits.

Lengths: a[digits].
*/
unsigned int NN_Bits (NN_DIGIT *a, unsigned int digits)
{
if ((digits = NN_Digits (a, digits)) == 0)
return (0);

return ((digits - 1) * NN_DIGIT_BITS + NN_DigitBits (a[digits-1]));
}

/* Returns the significant length of a in digits.

Lengths: a[digits].
*/
unsigned int NN_Digits (NN_DIGIT *a, unsigned int digits)
{
int i;

for (i = digits - 1; i >= 0; i--)
if (a[i])
break;

return (i + 1);
}



/* Returns the significant length of a in bits, where a is a digit.
*/
static unsigned int NN_DigitBits (NN_DIGIT a)
{
unsigned int i;

for (i = 0; i < NN_DIGIT_BITS; i++, a >>= 1)
if (a == 0)
break;

return (i);
}


int nagra_RSA(byte *in_msg,int keyselect,byte *n2,byte *n1,byte *e1, byte *decrypted)
{
NN_DIGIT E[MAX_NN_DIGITS], N[MAX_NN_DIGITS];//, N[MAX_NN_DIGITS];
NN_DIGIT M[MAX_NN_DIGITS], EMM[MAX_NN_DIGITS];//, E2[MAX_NN_DIGITS];
unsigned char hexstr[64];
int nDigits, eDigits;

NN_DecodeLE(EMM, MAX_NN_DIGITS, in_msg, 64);
//NN_DecodeLE(N, MAX_NN_DIGITS, n1, 64);
//NN_DecodeLE(E, MAX_NN_DIGITS, e1, 64);
NN_DecodeLE(N, MAX_NN_DIGITS, n2, 64);

R_memset((POINTER)E,0,sizeof(E));
R_memset((POINTER)M,0,sizeof(M));
//R_memset((POINTER)a,0,sizeof(a));
E[0]= 3;
nDigits = NN_Digits (EMM, MAX_NN_DIGITS);
eDigits = NN_Digits (E, MAX_NN_DIGITS);

NN_ModExp(M,EMM,E,eDigits,N,nDigits);
/* chk 5th bit of keyselect byte */
if(keyselect & 0x20){
/* swap signature */
memset(hexstr,0,sizeof(hexstr));
NN_EncodeLE(hexstr,64,M,MAX_NN_DIGITS);
memcpy(hexstr, in_msg -8, ;
NN_DecodeLE(M, MAX_NN_DIGITS, hexstr, 64);
}
keyselect &= 0xC0;
keyselect <<= 24;
M[15]|= keyselect;
/* copy bits from key select byte, 2 MSBits of key select byte into 2 MSBits of EMM
// this EMM key select byte = 00xxxxxx, so nothing to do
// a = (bigint) ((key select byte) & 0xC0);
// M |= (a << (63 * ); */
NN_DecodeLE(E, MAX_NN_DIGITS, e1, 64);
NN_DecodeLE(N, MAX_NN_DIGITS, n1, 64);
nDigits = NN_Digits (M, MAX_NN_DIGITS);
eDigits = NN_Digits (E, MAX_NN_DIGITS);
R_memset((POINTER)EMM,0,sizeof(EMM));

NN_ModExp(EMM,M,E,eDigits,N,nDigits);
memset(hexstr,0,sizeof(hexstr));
NN_Encode(hexstr,64,EMM,MAX_NN_DIGITS);
//R_memset((POINTER)a,0,sizeof(a));
R_memset((POINTER)M,0,sizeof(M));
R_memset((POINTER)EMM,0,sizeof(EMM));
R_memset((POINTER)E,0,sizeof(E));
R_memset((POINTER)N,0,sizeof(N));
//R_memset((POINTER)E2,0,sizeof(N2));
//R_memset((POINTER)E2,0,sizeof(N1));
if((hexstr[0]==0x2F)||(hexstr[0]==0x3F)){
memcpy(decrypted, hexstr, 64);
return 1;
}
return 0;
}

void makeMECM(byte *primes, byte *MECM, int *idx) {
NN_DIGIT E[MAX_NN_DIGITS], N[MAX_NN_DIGITS];//, N[MAX_NN_DIGITS];
NN_DIGIT P[MAX_NN_DIGITS/2], Q[MAX_NN_DIGITS/2], R[MAX_NN_DIGITS];
unsigned char hexstr[64];
int nDigits, eDigits, i;
R_memset((POINTER)N,0,sizeof(N));
NN_DecodeLE(P, MAX_NN_DIGITS/2, primes, 32);
NN_DecodeLE(Q, MAX_NN_DIGITS/2, primes+32, 32);
NN_Mult(N,P,Q,MAX_NN_DIGITS/2);
// N = P*Q is now new value of modular divisor
R_memset((POINTER)E,0,sizeof(E));
E[0]= 3;
// exponent E = 3
for( i=0; i<64; i++)
hexstr[i] = i;
NN_DecodeLE(R, MAX_NN_DIGITS, hexstr, 64);
nDigits = NN_Digits (R, MAX_NN_DIGITS);
eDigits = NN_Digits (E, MAX_NN_DIGITS);
// Compute R = (R**3) % N
NN_ModExp(R,R,E,eDigits,N,nDigits);
NN_EncodeLE(hexstr,64,R,MAX_NN_DIGITS);


*idx = hexstr[0] & 0xFF;
memcpy(MECM,hexstr + 1, 16);

}

void s2sse(byte *emm, byte *mod, byte *exp, byte *decrypted) {
NN_DIGIT E[MAX_NN_DIGITS], N[MAX_NN_DIGITS];//, N[MAX_NN_DIGITS];
NN_DIGIT M[MAX_NN_DIGITS], EMM[MAX_NN_DIGITS];//, E2[MAX_NN_DIGITS];
int nDigits, eDigits;

NN_DecodeLE(EMM, MAX_NN_DIGITS, emm, 90);
//NN_DecodeLE(N, MAX_NN_DIGITS, n1, 64);
NN_DecodeLE(E, MAX_NN_DIGITS, exp, 6);
NN_DecodeLE(N, MAX_NN_DIGITS, mod, 90);

R_memset((POINTER)M,0,sizeof(M));
//R_memset((POINTER)a,0,sizeof(a));
nDigits = NN_Digits (EMM, MAX_NN_DIGITS);
eDigits = NN_Digits (E, MAX_NN_DIGITS);

NN_ModExp(M,EMM,E,eDigits,N,nDigits);
memset(decrypted, 0, 90);
NN_EncodeLE(decrypted,90,M,MAX_NN_DIGITS);
}


************************************************** ************************************************** **********************
MN_ASM1

//---------------------------------------------------------------------------
/*
st20cc -cpp nn_main.c -p c2
st20run -d -t c2 nn_main.lku
*/

//#pragma hdrstop

//#include "nn.h"

//---------------------------------------------------------------------------

//#pragma package(smart_init)
/* NN.C - natural numbers routines
*/

/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
Inc., created 1991. All rights reserved.
*/

//#include "global.h"
//#include "rsaref.h"
#include "nn.h"
//#include "digit.h"
//#include <mem.h>
#include <string.h>

int conax_decrypt(byte *buf, byte len, byte *e1, byte *n1, byte *plainwords){
unsigned char out[64];
int i, index, nDigits, eDigits;
const byte hash[] = {0x05, 0x00, 0x05};

NN_DIGIT N1[MAX_NN_DIGITS];
NN_DIGIT E1[MAX_NN_DIGITS];
NN_DIGIT ecm[MAX_NN_DIGITS], decm[MAX_NN_DIGITS];

NN_Decode(N1,MAX_NN_DIGITS,n1, 64);
NN_Decode(E1,MAX_NN_DIGITS,e1, 64);

/* begin RSA decrypt */
for (i=len;i>0 {
index = i-64; /* begin from last 64 bytes of ECM */
if(i-64 < 0)
index = 0;

NN_Decode(ecm,MAX_NN_DIGITS,buf+index,64);
nDigits = NN_Digits (ecm, MAX_NN_DIGITS);
eDigits = NN_Digits (E1, MAX_NN_DIGITS);
NN_ModExp(decm,ecm,E1,eDigits,N1,nDigits);
NN_Encode(out,64,decm,MAX_NN_DIGITS);
memcpy(buf+index, out, 64);

if(i%60 && index)
i-=i%60;
else
i-=64;

}
R_memset((POINTER)N1,0,sizeof(N1));
R_memset((POINTER)ecm,0,sizeof(ecm));
R_memset((POINTER)decm,0,sizeof(decm));
R_memset((POINTER)E1,0,sizeof(E1));
if(memcmp(hash, buf+2, 3) == 0 &&
memcmp(buf+5, buf+len-5, 5) == 0) {
/* Signature correct, parse decrypted packet */
ParseECM(buf+10,len-10,plainwords);
return 1;
} else
/* Signature incorrect */
return 0;

}

void ParseECM(byte *buf, byte len, byte *plainwords) {
int i;
for(i=0; i<len; ) {
byte nano = buf[i++];
byte nanolen = buf[i++];

switch(nano) {
case 0x80:
case 0x82:
/* mlogprint(dbg, "Nano 80 %02x - Provider %02x %02x\n", nanolen, buf[i+1], buf[i+2]);
curr_id = (buf[i+1]<<16)|(buf[i+2]<<; */
ParseECM(buf+i+3, nanolen-3, plainwords);
break;
case 0x81:
/* mlogprint(dbg, "Nano 81 %02x - Provider %02x %02x\n", nanolen, buf[i], buf[i+1]);*/
ParseECM(buf+i+2, nanolen-2, plainwords);
break;
case 0x30:
/* mlogprint(dbg, "Nano 30 %02x - Control words\n", nanolen);
curr_id &= ~0xff;
curr_id |= buf[i+1]; */
if(plainwords) {
memcpy(plainwords, buf+i+10, ;
memcpy(plainwords+8, buf+i+2, ;
}
break;

default:
break;
}
i += nanolen;
}
}


void R_memset (
POINTER output, /* output block */
int value, /* value */
unsigned int len) /* length of block */
{
//if (len)
//memset (output, value, len);
__asm {
ldl len;//4;
wcnt;
stl len;//4;
chk_len:
ldl len; cj exit ;
ldl value; ldl output; stnl 0;
ldl output; ldnlp 1; stl output;
ldl len; adc -1;stl len; j chk_len ;
exit:
ret;
};


}

void R_memcpy (
POINTER output, /* output block */
POINTER input, /* input block */
unsigned int len) /* length of blocks */
{
if (len)
memcpy (output, input, len);
}

int R_memcmp (
POINTER firstBlock, /* first block */
POINTER secondBlock, /* second block */
unsigned int len) /* length of blocks */
{
if (len)
return (memcmp (firstBlock, secondBlock, len));
else
return (0);
}



/* Sets a = b / c, where a and c are digits.

Lengths: b[2].
Assumes b[1] < c and HIGH_HALF (c) > 0. For efficiency, c should be
normalized.
*/
void NN_DigitDiv (NN_DIGIT *a,NN_DIGIT b[2],NN_DIGIT c)
{
__asm {

ldl b; ldnl 1; // b[1]
ldl b; ldnl 0; // b[0]
ldl c ; // c
ldiv ; // b/c
ldl a; stnl 0; // *a = b/c
ret; // returns reminder
};
}

static unsigned int NN_DigitBits PROTO_LIST ((NN_DIGIT));

/* Decodes character string b into a, where character string is ordered
from most to least significant.

Lengths: a[digits], b[len].
Assumes b[i] = 0 for i < len - digits * NN_DIGIT_LEN. (Otherwise most
significant bytes are truncated.)
*/
void NN_Decode (NN_DIGIT *a,unsigned int digits, unsigned char *b,unsigned int len)
{
NN_DIGIT t;
int j;
unsigned int i, u;

for (i = 0, j = len - 1; i < digits && j >= 0; i++) {
t = 0;
for (u = 0; j >= 0 && u < NN_DIGIT_BITS; j--, u +=
t |= ((NN_DIGIT)b[j]) << u;
a[i] = t;
}

for (; i < digits; i++)
a[i] = 0;
}

/* Decodes character string b into a, where character string is ordered
from least to most significant.

Lengths: a[digits], b[len].
Assumes b[i] = 0 for i < len - digits * NN_DIGIT_LEN. (Otherwise most
significant bytes are truncated.)
*/
void NN_DecodeLE (NN_DIGIT *a,unsigned int digits, unsigned char *b,unsigned int len)
{
NN_DIGIT t; // temporary long var for decoding chars
int j; /* index of char string */
unsigned int i, u; /* i - index in DIGIT's array, u - number of bit in t */

for (i = 0, j = 0; i < digits && j < len; i++) {
t = 0;
for (u = 0; j < len && u < NN_DIGIT_BITS; j++, u +=
t |= ((NN_DIGIT)b[j]) << u;
a[i] = t;
}

for (; i < digits; i++)
a[i] = 0; /* pad the rest of digit's array with 0 */
}

/* Encodes b into character string a, where character string is ordered
from most to least significant.

Lengths: a[len], b[digits].
Assumes NN_Bits (b, digits) <= 8 * len. (Otherwise most significant
digits are truncated.)
*/
void NN_Encode (unsigned char *a,unsigned int len, NN_DIGIT *b,unsigned int digits)
{
NN_DIGIT t;
int j;
unsigned int i, u;

for (i = 0, j = len - 1; i < digits && j >= 0; i++) {
t = b[i];
for (u = 0; j >= 0 && u < NN_DIGIT_BITS; j--, u +=
a[j] = (unsigned char)(t >> u);
}

for (; j >= 0; j--)
a[j] = 0;
}

void NN_EncodeLE (unsigned char *a,unsigned int len, NN_DIGIT *b,unsigned int digits)
{
NN_DIGIT t;
int j;
unsigned int i, u;

for (i = 0, j = 0; i < digits && j < len; i++) {
t = b[i];
for (u = 0; j < len && u < NN_DIGIT_BITS; j++, u +=
a[j] = (unsigned char)(t >> u);
}

for (; j < len; j++)
a[j] = 0;
}

/* Assigns a = b.

Lengths: a[digits], b[digits].
*/
void NN_Assign (NN_DIGIT *a,NN_DIGIT *b,unsigned int digits)
{
unsigned int i;

for (i = 0; i < digits; i++)
a[i] = b[i];
}

/* Assigns a = 0.

Lengths: a[digits].
*/
void NN_AssignZero (
NN_DIGIT *a,
unsigned int digits)
{
unsigned int i;

for (i = 0; i < digits; i++)
a[i] = 0;
}

/* Computes a = b - c. Returns borrow.

Lengths: a[digits], b[digits], c[digits].
*/

NN_DIGIT NN_Sub (NN_DIGIT *a,NN_DIGIT *b,NN_DIGIT *c,unsigned int digits)
{
NN_DIGIT borrow,*A,*B,*C;
unsigned int i;

borrow = 0;
A=a;
B=b;
C=c;
//i=&c[digits];

//for (i = 0; i < digits; i++) {
/*if ((ai = b[i] - borrow) > (MAX_NN_DIGIT - borrow))
ai = MAX_NN_DIGIT - c[i];
else if ((ai -= c[i]) > (MAX_NN_DIGIT - c[i]))
borrow = 1;
else
borrow = 0;*/

__asm {
ldl digits;ldl C; wsub; stl i;
loop:
ldl borrow; // borrow
ldl B; ldnl 0; // b[i]
ldl C; ldnl 0; // c[i]
ldiff;
ldl A; stnl 0; // a[i]=b[i]-c[i]-borrow
stl borrow;//2 // store borrow
ldl A; ldnlp 1; stl A;
ldl B; ldnlp 1; stl B;
ldl C; ldnlp 1; stl C;
ldl i; ldl C; diff; eqc 0; cj loop;
};
return (borrow);
}


/* Computes a = b * c.

Lengths: a[2*digits], b[digits], c[digits].
Assumes digits < MAX_NN_DIGITS.
*/

void NN_Mult (NN_DIGIT *a,NN_DIGIT *b,NN_DIGIT *c,unsigned int digits)
{
//NN_DIGIT t[2*MAX_NN_DIGITS];
unsigned int bDigits, cDigits, i,j, carry, tmp[2];
NN_DIGIT *C, *A, *B, *B1;
//NN_AssignZero (t, 2 * digits);

bDigits = NN_Digits (b, digits);
cDigits = NN_Digits (c, digits);
for ( i = 0; i < (digits*2);i++) a[i]=0;
C=&c[0];
for ( i = 0; i < cDigits; i++) {
carry = 0;
//C=&c[i];
A=&a[i];
B=&b[0];
B1=b + bDigits;
//for (j = 0; j < bDigits; j++) {
j = 0;
while(B < B1) {
/*tmp = c[i] * b[j] + a[i+j] + carry;
carry = tmp/BASE;
a[i+j] = tmp - carry*BASE;*/
__asm {
ldl carry;
ldl B; ldnl 0; // b[j]
ldl C; ldnl 0; // c[i]
lmul;

st tmp[0];// c[i] * b[j]+carry
st tmp[1]; // product carry out
ldc 0;
ldl A; ldnl 0;// a[i+j]
ld tmp[0];
lsum; // c[i] * b[j] + carry + a[i+j]
ldl A; stnl 0; // a[i+j] += c[i] * b[j] + carry
ld tmp[1]; bsub; stl carry; // new carry
ldl B; ldnlp 1; stl B;
ldl A; ldnlp 1; stl A;
};
}
A[j] = carry;
//C += 4;
__asm {
ldl C;
ldnlp 1;
stl C;
};
}
}

/* Computes a = b * 2^c (i.e., shifts left c bits), returning carry.

Lengths: a[digits], b[digits].
Requires c < NN_DIGIT_BITS.
*/
NN_DIGIT NN_LShift (NN_DIGIT *a,NN_DIGIT *b,unsigned int c,unsigned int digits)
{
NN_DIGIT carry, *A, *B, *B1;
//unsigned int i, t;

if (c >= NN_DIGIT_BITS)
return (0);
carry = 0;
A = a;
B = b;
B1 = &b[digits];
// for (i = 0; i < digits; i++) {
while (B < B1) {
__asm {
ldc 0;
ldl B;
ldnl 0;
ldl c;
lshl;
ldl carry;
or;
ldl A;
stnl 0;
stl carry;
ldl A; ldnlp 1; stl A;
ldl B; ldnlp 1; stl B;
};
}

return (carry);
}

/* Computes a = c div 2^c (i.e., shifts right c bits), returning carry.

Lengths: a[digits], b[digits].
Requires: c < NN_DIGIT_BITS.
*/
NN_DIGIT NN_RShift (NN_DIGIT *a,NN_DIGIT *b,unsigned int c,unsigned int digits)
{
NN_DIGIT bi, carry;
int i;
unsigned int t;

if (c >= NN_DIGIT_BITS)
return (0);

t = NN_DIGIT_BITS - c;

carry = 0;

for (i = digits - 1; i >= 0; i--) {
bi = b[i];
a[i] = (bi >> c) | carry;
carry = c ? (bi << t) : 0;
}

return (carry);
}

/* Computes a = b mod c.

Lengths: a[cDigits], b[bDigits], c[cDigits].
Assumes c > 0, bDigits < 2 * MAX_NN_DIGITS, cDigits < MAX_NN_DIGITS.
*/

void NN_Mod ( NN_DIGIT *b, NN_DIGIT *c,unsigned int cDigits, NN_DIGIT *d,unsigned int dDigits)
{
NN_DIGIT ai, cc[2*MAX_NN_DIGITS+1], dd[MAX_NN_DIGITS], t, tt[2],*C,*D, *E;
int i,j,k;
unsigned int ddDigits, shift, borrow;

ddDigits = NN_Digits (d, dDigits);
if (ddDigits == 0)
return;

/* Normalize operands.
*/
shift = NN_DIGIT_BITS - NN_DigitBits (d[ddDigits-1]); // number of zero bits in high digit of
NN_AssignZero (cc, ddDigits);
cc[cDigits] = NN_LShift (cc, c, shift, cDigits); //cc = c << shift, highest digit of cc is carry from shift
NN_LShift (dd, d, shift, ddDigits); // dd is normalized divisor
t = dd[ddDigits-1]; // t - high digit of dd
for (i = cDigits-ddDigits; i >= 0; i--) {
/* Underestimate quotient digit and subtract.
*/
if (t == MAX_NN_DIGIT)
ai = cc[i+ddDigits]; // ai= higher digit of divident
else
NN_DigitDiv (&ai, &cc[i+ddDigits-1], t + 1); /* ai=cc[i+ddDigits-1]/(t + 1) */ //else ai is quotient of division to t+1

//cc[i+ddDigits] -= NN_SubDigitMult (&cc[i], &cc[i], ai, dd, ddDigits);
// ------------------------------------------------------------------------
// cc[i...]=cc[i...] - ai*dd
if (ai == 0) {
borrow=0;
goto _end;
}
C=&cc[i];
D=&dd[0];
E=cc + i + ddDigits;
borrow = 0;
while (C < E) {
// NN_DigitMult (t, c, d[i]);
__asm {
ldc 0;
ldl D;
ldnl 0; // d[j]
ldl ai;
lmul ;
st tt[0];//stl 3 // t[0] = D[j]*ai
st tt[1];//stl 4 // t[1] - product carry
//- borrow=ldiff(a[i],b[i],borrow);
ldc 0;
ldl C;
ldnl 0; // C[j]
ldl borrow; // borrow
ldiff;
rev;
stl borrow; // borrow <- C[j]-borrow
//- borrow=borrow+ldiff(a[i],a[i],t[0]); ai=ai - t0 -borrow
ldc 0;
rev;
ld tt[0];//ldl 3 // t[0]
ldiff;
ldl C;
stnl 0;
ldl borrow;//2
bsub;
stl borrow;//2 // borrow += new borrow
ldl D; ldnlp 1; stl D; // D++
ldl C; ldnlp 1; stl C; // C++
};
borrow += tt[1];
}
_end:
cc[i+ddDigits] -= borrow;
//--------------------------------------------------------
/* Correct estimate.
*/

C=&cc[i];

while (1) {
//ai++;
if(C[ddDigits]) goto _cont;
//if(NN_Cmp (&cc[i], dd, ddDigits) < 0) break;
k=1;
for(j=ddDigits-1;j>=0;j--){
if(C[j]>dd[j])
goto _chk;
if(C[j]<dd[j]) {
k=0;
goto _chk;
}
}
_chk:
if(!k) break;
_cont:
cc[i+ddDigits] -= NN_Sub (&cc[i], &cc[i], dd, ddDigits);
}

//a[i] = ai;
}

/* Restore result.
*/
NN_AssignZero (b, dDigits);
NN_RShift (b, cc, shift, ddDigits); // b = cc >> shift --
}


/* Computes a = b * c mod d.

Lengths: a[digits], b[digits], c[digits], d[digits].
Assumes d > 0, digits < MAX_NN_DIGITS.
*/
void NN_ModMult (NN_DIGIT *a, NN_DIGIT *b, NN_DIGIT *c, NN_DIGIT *d, unsigned int digits)
{
NN_DIGIT t[2*MAX_NN_DIGITS];

NN_Mult (t, b, c, digits);
NN_Mod (a, t, 2 * digits, d, digits);

/* Zeroize potentially sensitive information.
*/
R_memset ((POINTER)t, 0, sizeof (t));
}

/* Computes a = b^c mod d.

Lengths: a[dDigits], b[dDigits], c[cDigits], d[dDigits].
Assumes d > 0, cDigits > 0, dDigits < MAX_NN_DIGITS.
*/
void NN_ModExp (NN_DIGIT *a, NN_DIGIT *b, NN_DIGIT *c,unsigned int cDigits, NN_DIGIT *d,unsigned int dDigits)
{
NN_DIGIT bPower[3][MAX_NN_DIGITS], ci, t[MAX_NN_DIGITS];
int i;
unsigned int ciBits, j, s;

/* Store b, b^2 mod d, and b^3 mod d.
*/
NN_Assign (bPower[0], b, dDigits);
NN_ModMult (bPower[1], bPower[0], b, d, dDigits);
NN_ModMult (bPower[2], bPower[1], b, d, dDigits);

NN_ASSIGN_DIGIT (t, 1, dDigits);

cDigits = NN_Digits (c, cDigits);
for (i = cDigits - 1; i >= 0; i--) {
ci = c[i];
ciBits = NN_DIGIT_BITS;

/* Scan past leading zero bits of most significant digit.
*/
if (i == (int)(cDigits - 1)) {
while (! DIGIT_2MSB (ci)) {
ci <<= 2;
ciBits -= 2;
}
}

for (j = 0; j < ciBits; j += 2, ci <<= 2) {
/* Compute t = t^4 * b^s mod d, where s = two MSB's of ci.
*/
NN_ModMult (t, t, t, d, dDigits);
NN_ModMult (t, t, t, d, dDigits);
if ((s = DIGIT_2MSB (ci)) != 0)
NN_ModMult (t, t, bPower[s-1], d, dDigits);
}
}

NN_Assign (a, t, dDigits);

/* Zeroize potentially sensitive information.
*/
R_memset ((POINTER)bPower, 0, sizeof (bPower));
R_memset ((POINTER)t, 0, sizeof (t));
}


/* Returns the significant length of a in digits.

Lengths: a[digits].
*/
unsigned int NN_Digits (NN_DIGIT *a, unsigned int digits)
{
int i;

for (i = digits - 1; i >= 0; i--)
if (a[i])
break;

return (i + 1);
}
/* Returns the significant length of a in bits, where a is a digit.
*/
static unsigned int NN_DigitBits (NN_DIGIT a)
{
unsigned int i;

for (i = 0; i < NN_DIGIT_BITS; i++, a >>= 1)
if (a == 0)
break;

return (i);
}


int nagra_RSA(byte *in_msg,int keyselect,byte *n2,byte *n1,byte *e1, byte *decrypted)
{
NN_DIGIT E[MAX_NN_DIGITS], N[MAX_NN_DIGITS];//, N[MAX_NN_DIGITS];
NN_DIGIT M[MAX_NN_DIGITS], EMM[MAX_NN_DIGITS];//, E2[MAX_NN_DIGITS];
unsigned char hexstr[64];
int nDigits, eDigits;

NN_DecodeLE(EMM, MAX_NN_DIGITS, in_msg, 64);
//NN_DecodeLE(N, MAX_NN_DIGITS, n1, 64);
//NN_DecodeLE(E, MAX_NN_DIGITS, e1, 64);
NN_DecodeLE(N, MAX_NN_DIGITS, n2, 64);

R_memset((POINTER)E,0,sizeof(E));
R_memset((POINTER)M,0,sizeof(M));
//R_memset((POINTER)a,0,sizeof(a));
E[0]= 3;
nDigits = NN_Digits (EMM, MAX_NN_DIGITS);
eDigits = NN_Digits (E, MAX_NN_DIGITS);

NN_ModExp(M,EMM,E,eDigits,N,nDigits);
/* chk 5th bit of keyselect byte */
if(keyselect & 0x20){
/* swap signature */
memset(hexstr,0,sizeof(hexstr));
NN_EncodeLE(hexstr,64,M,MAX_NN_DIGITS);
memcpy(hexstr, in_msg -8, ;
NN_DecodeLE(M, MAX_NN_DIGITS, hexstr, 64);
}
keyselect &= 0xC0;
keyselect <<= 24;
M[15]|= keyselect;
/* copy bits from key select byte, 2 MSBits of key select byte into 2 MSBits of EMM
// this EMM key select byte = 00xxxxxx, so nothing to do
// a = (bigint) ((key select byte) & 0xC0);
// M |= (a << (63 * ); */
NN_DecodeLE(E, MAX_NN_DIGITS, e1, 64);
NN_DecodeLE(N, MAX_NN_DIGITS, n1, 64);
nDigits = NN_Digits (M, MAX_NN_DIGITS);
eDigits = NN_Digits (E, MAX_NN_DIGITS);
R_memset((POINTER)EMM,0,sizeof(EMM));

NN_ModExp(EMM,M,E,eDigits,N,nDigits);
memset(hexstr,0,sizeof(hexstr));
NN_Encode(hexstr,64,EMM,MAX_NN_DIGITS);
//R_memset((POINTER)a,0,sizeof(a));
R_memset((POINTER)M,0,sizeof(M));
R_memset((POINTER)EMM,0,sizeof(EMM));
R_memset((POINTER)E,0,sizeof(E));
R_memset((POINTER)N,0,sizeof(N));
//R_memset((POINTER)E2,0,sizeof(N2));
//R_memset((POINTER)E2,0,sizeof(N1));
if((hexstr[0]==0x2F)||(hexstr[0]==0x3F)){
memcpy(decrypted, hexstr, 64);
return 1;
}
return 0;
}

void makeMECM(byte *primes, byte *MECM, int *idx) {
NN_DIGIT E[MAX_NN_DIGITS], N[MAX_NN_DIGITS];//, N[MAX_NN_DIGITS];
NN_DIGIT P[MAX_NN_DIGITS/2], Q[MAX_NN_DIGITS/2], R[MAX_NN_DIGITS];
unsigned char hexstr[64];
int nDigits, eDigits, i;
R_memset((POINTER)N,0,sizeof(N));
NN_DecodeLE(P, MAX_NN_DIGITS/2, primes, 32);
NN_DecodeLE(Q, MAX_NN_DIGITS/2, primes+32, 32);
NN_Mult(N,P,Q,MAX_NN_DIGITS/2);
// N = P*Q is now new value of modular divisor
R_memset((POINTER)E,0,sizeof(E));
E[0]= 3;
// exponent E = 3
for( i=0; i<64; i++)
hexstr[i] = i;
NN_DecodeLE(R, MAX_NN_DIGITS, hexstr, 64);
nDigits = NN_Digits (R, MAX_NN_DIGITS);
eDigits = NN_Digits (E, MAX_NN_DIGITS);
// Compute R = (R**3) % N
NN_ModExp(R,R,E,eDigits,N,nDigits);
NN_EncodeLE(hexstr,64,R,MAX_NN_DIGITS);


*idx = hexstr[0] & 0xFF;
memcpy(MECM,hexstr + 1, 16);

}

void s2sse(byte *emm, byte *mod, byte *exp, byte *decrypted) {
NN_DIGIT E[MAX_NN_DIGITS], N[MAX_NN_DIGITS];//, N[MAX_NN_DIGITS];
NN_DIGIT M[MAX_NN_DIGITS], EMM[MAX_NN_DIGITS];//, E2[MAX_NN_DIGITS];
int nDigits, eDigits;

NN_DecodeLE(EMM, MAX_NN_DIGITS, emm, 90);
//NN_DecodeLE(N, MAX_NN_DIGITS, n1, 64);
NN_DecodeLE(E, MAX_NN_DIGITS, exp, 6);
NN_DecodeLE(N, MAX_NN_DIGITS, mod, 90);

R_memset((POINTER)M,0,sizeof(M));
//R_memset((POINTER)a,0,sizeof(a));
nDigits = NN_Digits (EMM, MAX_NN_DIGITS);
eDigits = NN_Digits (E, MAX_NN_DIGITS);

NN_ModExp(M,EMM,E,eDigits,N,nDigits);
memset(decrypted, 0, 90);
NN_EncodeLE(decrypted,90,M,MAX_NN_DIGITS);
}


************************************************** ************************************************** **********************
SECA
/* secalinux: Emulates a SECA Smartcard

Copyright (C) 2000 2tor ([email protected])
Part of original code and algorithms by Fullcrack ([email protected])

This program 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 program 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


This software is for educational purposes only. It should not be used
to ilegally watch TV channels.

Version 0.1, December 2000.
*/

#ifndef byte
#define byte unsigned char
#endif
/* some necessary stuff within emu buffer */
#define S_PPUA_OFFSET 0x10
#define S_ID_LEN 2
#define S_PPUA_LEN 4
#define S_PROV_NUM 8

#define OPKEY_OFFSET 0x210
#define OPKEY_LEN 0xB
#define OPKEY_END 0xFFE
#define SIG_UPD_OFFSET 0x203
#define KEY_IDX_OFFSET 0x204
#define UPD_FLAG_OFFSET 0x202
#define KEY_IDX2_OFFSET 0xFFC
#define KEY_IDX3_OFFSET 0xFFD


void decrypt_seca( unsigned char *k,unsigned char *d, byte *T1, byte *T2 );
void encrypt_seca( unsigned char *k,unsigned char *d, byte *T1, byte *T2 );
int seca_ecm(byte *source, byte *dw,byte *buf_emu);
int seca_emm(byte *source, byte *emu_buf);
int get_provN(byte *ident, byte *buf_emu);
************************************************** ************************************************** **********************