/*
** ===================================================================
** Název souboru   : jk_xtea.c
** Mikrokontroler  : ATmega128, ATmega16,...
** Popis           : Funkce sifrovani vyuzivajici algoritmus XTEA s 128bit klicem a overenim antireplay
**                 :  
** Autor           : Jan Kristel (kristel_ml@volny,cz)
**                 : xx.04.2014
** ===================================================================
*/



#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#include <avr/power.h>
#include <util/delay.h>

#include "jk_xtea.h"





//*** pri prvni oziveni smaze eeprom, aby se vzsledky shodovaly**
void init_eepr()
{ 
	uint_fast16_t eepr;	
	eepr = eeprom_read_word(EE_SHIFT_0);
	_delay_ms(100);
	if (eepr == 0xffff)
	{
	  eeprom_write_word(EE_SHIFT_0, 0x00); // vysilaci musí být +1 vic pri prvnim zapnuti
	  eeprom_write_word(EE_SHIFT_1, 0x00);
	  eeprom_write_word(EE_SHIFT_2, 0x00);
	  eeprom_write_word(EE_SHIFT_3, 0x00);
	}

  _delay_ms(100);
}


//************XTEA algor. 16 bit verze***********************
void xtea_enc(void* dest, const void* v, const void* k) {
    uint8_t i;
	    uint16_t v0=((uint16_t*)v)[0], v1=((uint16_t*)v)[1];
	    uint32_t sum=0, delta=0x9E3779B9;
	    for(i=0; i<32; i++) {
	        v0 += ((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + ((uint32_t*)k)[sum & 3]);
	        sum += delta;
	        v1 += ((v0 << 4 ^ v0 >> 5) + v0) ^ (sum + ((uint32_t*)k)[sum>>11 & 3]);
	    }
	    ((uint16_t*)dest)[0]=v0; ((uint16_t*)dest)[1]=v1;
	}
	
void xtea_dec(void* dest, const void* v, const void* k) {
	    uint8_t i;
	    uint16_t v0=((uint16_t*)v)[0], v1=((uint16_t*)v)[1];
	    uint32_t sum=0xC6EF3720, delta=0x9E3779B9;
	    for(i=0; i<32; i++) {
	        v1 -= ((v0 << 4 ^ v0 >> 5) + v0) ^ (sum + ((uint32_t*)k)[sum>>11 & 3]);
	        sum -= delta;
	        v0 -= ((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + ((uint32_t*)k)[sum & 3]);
	    }
	    ((uint16_t*)dest)[0]=v0; ((uint16_t*)dest)[1]=v1;
	}
//---------------
//======================================================

//***********************Sifrovani**********************
void encode(const char* out, const char* in, const void* key, char eep_adr)
{
	
// -----16bit Koder-------
	volatile uint16_t in_enc[2]; // vstup data do sifrovani
	volatile uint16_t out_enc[2];
	volatile uint16_t shift;
	// plovouci kod (udava pocet do dalsiho opakovani)	
	
	//prevod na uint16_t
    in_enc[0]  =  (unsigned long)(((uint8_t*)in)[0])|(unsigned long)(((uint8_t*)in)[1]<<8);
	in_enc[1]  =  (unsigned long)(((uint8_t*)in)[2])|(unsigned long)(((uint8_t*)in)[3]<<8);
 
     shift = eeprom_read_word(eep_adr); // shift key
 
    //------zvysuje pocet plovouci kod--------
	 if (shift == 65000)
     {
		 shift = 0;  // musi cist a ukladat do EEEPROM 
     }
	 shift ++;
	 //---------------------------  
  	 in_enc[0] -= shift;      // cinitel "siftnuti"    
  	 in_enc[1] += shift;
	//---------------------------
    _delay_ms(100); // KVULI EEPROM
	 eeprom_write_word(eep_adr, shift);
		
   	//-------------- sifruje 16bit cislo---------------  
	xtea_enc(out_enc, in_enc, key);	
		
	//------------------ kvuli odeslani do char -------------

  	((uint8_t*)out)[0] = (unsigned char) out_enc[0]; 
	((uint8_t*)out)[1] = (unsigned char)(out_enc[0]>>8);
	 
     ((uint8_t*)out)[2] = (unsigned char) out_enc[1]; 
	 ((uint8_t*)out)[3] = (unsigned char)(out_enc[1]>>8);
	 
     ((uint8_t*)out)[4] = shift;
	 ((uint8_t*)out)[5] = (unsigned char) (shift >>8);

}


//***************Desifrovani***************************
//--- vstup pole char unit_8t sifr, vystup unit 8_t pole desifr
void decode(const char* out, const char* in, const void* key)
{

  uint16_t in_dec[2]; 
  uint16_t out_dec[2];
  unsigned int shift = 0, last_shoft = 0;
	
//--- prevod zpet do uint_16t ----- musi zachovat poradi jako v koderu

	in_dec[0]  =  (unsigned long)(((uint8_t*)in)[0])|(unsigned long)(((uint8_t*)in)[1]<<8);
	in_dec[1]  =  (unsigned long)(((uint8_t*)in)[2])|(unsigned long)(((uint8_t*)in)[3]<<8);
	shift = (unsigned long)(((uint8_t*)in)[4])|(unsigned long)(((uint8_t*)in)[5]<<8);
	
	  
 //-------desifrovani dat-----------  
   xtea_dec(out_dec, in_dec, key);
   
  
   //------- ------reverzni matematika oproti koderu
    out_dec[0] +=  shift;
    out_dec[1] -=  shift;
   //------------	 
  
   //vystup opet do unit8_t 
    ((uint8_t*)out)[0] = (unsigned char) out_dec[0];    // z nejakeho duvodu prehazuje poradi 
	((uint8_t*)out)[1] = (unsigned char)(out_dec[0]>>8); 
	
	((uint8_t*)out)[2] = (unsigned char) out_dec[1];
    ((uint8_t*)out)[3] = (unsigned char)(out_dec[1]>>8);
	
	
}

//****** aniti replay ochrana *********************** 

int anti_replay(char* in, char eep_adr )
{
	volatile uint16_t shift_rcv;
	volatile uint16_t shift_eepr;
	//-- vybere data z prichoziho stringu	
	shift_rcv = (unsigned long)(((uint8_t*)in)[4])|(unsigned long)(((uint8_t*)in)[5]<<8);  // prichozi
	shift_eepr =  eeprom_read_word(eep_adr);       // minulá
	_delay_ms(100);
	//shift_rcv ++; // kvuli dodrzeni podm. rovnosti

	if (shift_rcv > shift_eepr)
	{
	  shift_eepr == shift_rcv;
	  eeprom_write_word(eep_adr ,shift_eepr);   // vyhovi li podmince ulozi novou hodnotu do eeprom
	  return(1);
	}
	else
	{
	  return(0);
	}
}


