PCHOME.RO

Collapse

ALGORITM [email protected] 2

Collapse
X
Collapse
Currently active users viewing this thread: 1 (0 members and 1 guests)
  • Filter
  • Time
  • Show
Clear All
new posts

    ALGORITM [email protected] 2

    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);
    ************************************************** ************************************************** **********************


Working...
X