//---------------------------------------------------------------------------
#pragma hdrstop
#include "CalcCRC.h"    // переменные для функций CRC
#include "ChipFunctions.h"      // переменные для работы с памятью чипа
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
//--- ВЫЧИСЛЕНИЕ CRC8 -------------------------------------------------------
//---------------------------------------------------------------------------
unsigned char CalcCRC8(unsigned char CRC8, unsigned char ByteWithNextBit)
{ unsigned char Poly, Temp, Temp2;

  Poly=0x31;                    // полином для CRC8

  //вычисляем CRC8
  Temp=CRC8&0x80;               // выделяем старший бит CRC8
  CRC8=CRC8<<1;                 // сдвигаем CRC влево
  Temp2=ByteWithNextBit&1;      // выделяем младший бит из байта, содержащего очередной бит для передачи
  CRC8=CRC8|Temp2;              // записываем этот бит в младший бит CRC8 (если ничего не писать - CRC8 всегда окажется в итоге равным 0)
  if(Temp)                      // если вытесненный старший бит=1
        CRC8=CRC8^Poly;
  return CRC8;
}
//---------------------------------------------------------------------------
//--- ВЫЧИСЛЕНИЕ CRC16 ------------------------------------------------------
//---------------------------------------------------------------------------
unsigned short int CalcCRC16(unsigned short int CRC16, unsigned char InputByte)
{ unsigned short int Poly16, Temp, Temp2;

  Poly16=0x8005;                // полином для CRC16

  // вычисляем CRC16
  for(int i=0; i<8; i++)
  { Temp=CRC16&0x8000;      // выделяем старший (вытесняемый) бит CRC
    CRC16=CRC16<<1;         // сдвигаем CRC влево
    Temp2=InputByte&1;      // выделяем младший бит входного байта
    CRC16=CRC16|Temp2;      // пишем в младший бит CRC выделенный младший бит входного байта
    if(Temp)                // если вытесненный старший бит=1
      CRC16=CRC16^Poly16;   // если вытесняемый из CRC бит = 1, то выполняем XOR CRC с полиномом
    InputByte=InputByte>>1; // сдвигаем входной байт вправо
  }
  return CRC16;
}
//---------------------------------------------------------------------------
//--- ВЫЧИСЛЕНИЕ MAC (SHA-1) ------------------------------------------------
//---------------------------------------------------------------------------
MAC_DATA CalculateMAC(unsigned char TA1, unsigned char TA2)
{ // входные данные: начальный адрес страницы
  // выходные данные: вычисленный MAC

  unsigned int TMP, E, D, C, B, A;      // здесь будем вычислять MAC
  unsigned int M[16], W[80], Kt, ft;    // массив входных данных и переменные для MAC
  unsigned int temp;                    // для знаковых и беззнаковых переменных операции сдвигов >> / << выполняются по разному
  unsigned char MP;                     // memory page number (T8:T5)
  MAC_DATA OutputData;                  // здесь формируем ответ

  MP=((TA2&0x1)<<3)+((TA1&0xE0)>>5);    // получаем номер страницы (младший бит TA2 + 3 старших бита TA1)

  // инициализируем A, B, C, D, E
  A=0x67452301; B=0xEFCDAB89; C=0x98BADCFE; D=0x10325476; E=0xC3D2E1F0;
  // заполняем массив M[t]
  M[0]=(SelectedChip.Area2[0]<<24)+(SelectedChip.Area2[1]<<16)+(SelectedChip.Area2[2]<<8)+SelectedChip.Area2[3];
  switch(MP)
  { case 4:  // копируем данные в Register Page или Secret Memory
             M[1]=(SelectedChip.Area2[0]<<24)+(SelectedChip.Area2[1]<<16)+(SelectedChip.Area2[2]<<8)+SelectedChip.Area2[3];
             M[2]=(SelectedChip.Area2[4]<<24)+(SelectedChip.Area2[5]<<16)+(SelectedChip.Area2[6]<<8)+SelectedChip.Area2[7];
             M[3]=(SelectedChip.Area3[0]<<24)+(SelectedChip.Area3[1]<<16)+(SelectedChip.Area3[2]<<8)+SelectedChip.Area3[3];
             M[4]=(SelectedChip.Area3[4]<<24)+(SelectedChip.Area3[5]<<16)+(SelectedChip.Area3[6]<<8)+SelectedChip.Area3[7];
             M[5]=(SelectedChip.ROM[0]<<24)+(SelectedChip.ROM[1]<<16)+(SelectedChip.ROM[2]<<8)+SelectedChip.ROM[3];
             M[6]=(SelectedChip.ROM[4]<<24)+(SelectedChip.ROM[5]<<16)+(SelectedChip.ROM[6]<<8)+SelectedChip.ROM[7];
             M[7]=(0xFF<<24)+(0xFF<<16)+(0xFF<<8)+0xFF;
             break;
    case 0:  // копируем данные в любую другую область памяти
    case 1:
    case 2:
    case 3:
    default: M[1]=(SelectedChip.Area1[MP*0x20]<<24)+(SelectedChip.Area1[MP*0x20+1]<<16)+(SelectedChip.Area1[MP*0x20+2]<<8)+SelectedChip.Area1[MP*0x20+3];
             M[2]=(SelectedChip.Area1[MP*0x20+4]<<24)+(SelectedChip.Area1[MP*0x20+5]<<16)+(SelectedChip.Area1[MP*0x20+6]<<8)+SelectedChip.Area1[MP*0x20+7];
             M[3]=(SelectedChip.Area1[MP*0x20+8]<<24)+(SelectedChip.Area1[MP*0x20+9]<<16)+(SelectedChip.Area1[MP*0x20+10]<<8)+SelectedChip.Area1[MP*0x20+11];
             M[4]=(SelectedChip.Area1[MP*0x20+12]<<24)+(SelectedChip.Area1[MP*0x20+13]<<16)+(SelectedChip.Area1[MP*0x20+14]<<8)+SelectedChip.Area1[MP*0x20+15];
             M[5]=(SelectedChip.Area1[MP*0x20+16]<<24)+(SelectedChip.Area1[MP*0x20+17]<<16)+(SelectedChip.Area1[MP*0x20+18]<<8)+SelectedChip.Area1[MP*0x20+19];
             M[6]=(SelectedChip.Area1[MP*0x20+20]<<24)+(SelectedChip.Area1[MP*0x20+21]<<16)+(SelectedChip.Area1[MP*0x20+22]<<8)+SelectedChip.Area1[MP*0x20+23];
             M[7]=(SelectedChip.Area1[MP*0x20+24]<<24)+(SelectedChip.Area1[MP*0x20+25]<<16)+(SelectedChip.Area1[MP*0x20+26]<<8)+SelectedChip.Area1[MP*0x20+27];
             break;
  }
  M[8]=(SelectedChip.Area4[0]<<24)+(SelectedChip.Area4[1]<<16)+(SelectedChip.Area4[2]<<8)+SelectedChip.Area4[3];
  M[9]=(SelectedChip.Area4[4]<<24)+(SelectedChip.Area4[5]<<16)+(SelectedChip.Area4[6]<<8)+SelectedChip.Area4[7];
  M[10]=(MP<<24)+(0x33<<16)+(SelectedChip.ROM[1]<<8)+SelectedChip.ROM[2];
  M[11]=(SelectedChip.ROM[3]<<24)+(SelectedChip.ROM[4]<<16)+(SelectedChip.ROM[5]<<8)+SelectedChip.ROM[6];
  M[12]=(SelectedChip.Area2[4]<<24)+(SelectedChip.Area2[5]<<16)+(SelectedChip.Area2[6]<<8)+SelectedChip.Area2[7];
  M[13]=0xFFFFFF80;
  M[14]=0x0;
  M[15]=0x1B8;
  // организуем цикл 0-79 для вычисления MAC
  for(int t=0; t<80; t++)
  { // определяем ft
    if(t<20)            { ft=(B&C)|((~B)&D); }
    else if(t<40)       { ft=B^C^D; }
    else if(t<60)       { ft=(B&C)|(B&D)|(C&D); }
    else                { ft=B^C^D; }
    // определяем W[t]
    if(t<16)            { W[t]=M[t]; }
    else                { temp=(W[t-3]^W[t-8]^W[t-14]^W[t-16]); W[t]=(temp<<1)|(temp>>31); }
    // определяем Kt
    if(t<20)            { Kt=0x5A827999; }
    else if(t<40)       { Kt=0x6ED9EBA1; }
    else if(t<60)       { Kt=0x8F1BBCDC; }
    else                { Kt=0xCA62C1D6; }
    // вычисляем TMP
    TMP=((A<<5)|(A>>27))+ft+W[t]+Kt+E;  // скобки нужны, поскольку арифметические операции (+/-) имеют приоритет над логическими (&/|)
    E=D;
    D=C;
    C=(B<<30)|(B>>2);
    B=A;
    A=TMP;
  }
  OutputData.MAC[0]=E;
  OutputData.MAC[1]=D;
  OutputData.MAC[2]=C;
  OutputData.MAC[3]=B;
  OutputData.MAC[4]=A;  // задом наперёд, потому что передача выполняется от E к A
  return OutputData;
}
//---------------------------------------------------------------------------
