#include<iostream>
#include<vector>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<cstdlib>

/* C Zeugs fuer Curses Oberflaeche */

#include<ncurses.h>
#include<unistd.h>
// #include<signal.h>

#define RED 1
#define WHITE 2


const std::vector<unsigned int>::size_type n =16;

template<int N> class RC4 {
public:
  std::vector<unsigned int> S;
  std::vector<unsigned int>::size_type j,i;
  
  RC4(std::vector<unsigned int> key) : S(N) {
    for (i=0; i<N; ++i) 
      S[i] = i;
    j = 0;
    for (i=0; i<N; ++i) {
      j = (j + S[i] + key[i % key.size()]) % N;
      std::swap(S[i],S[j]);
    }
    
    i = 0; j =0;
  }

  unsigned int next() {
    i = (i+1) % N;
    j = (j+S[i]) %N;
    std::swap(S[i],S[j]);
    std::vector<unsigned int>::size_type t = (S[i]+S[j]) % N;
    return S[t];
  }
};


int main() {
  initscr();
  keypad(stdscr, TRUE);        
  (void) nonl(); 
  (void) cbreak();         
  (void) noecho();             
  start_color();                
  init_pair(RED, COLOR_YELLOW, COLOR_BLACK);  
  init_pair(WHITE, COLOR_WHITE, COLOR_BLACK);  
     

  move(1,2); 
  addstr("Angriff auf RC4 Demo (1-Runden Attacke)");

  move(3,2);
  printw("Reduzierte Version n = %i",n);

  refresh();

  srand(time(0));

  std::vector<unsigned int> zaehler(n,0);

  unsigned int K = rand() %n;
  std::vector<unsigned int> key(30);
  key[0] = 0;
  key[1] = K;

  move(5,2);
  printw("K[0] = 0 (bekannt)    K[1] = %d (unbekannt)",K);

  refresh();


  for(std::vector<unsigned int>::size_type k =0 ; k < zaehler.size(); ++k) {
    if (k==K) 
      attrset(COLOR_PAIR(RED) ^ A_BOLD);   
    move(10,k*5+1);
    printw("%3d",k);
    move(12,k*5+1);
    printw("%3d",zaehler[k]);
    attrset(COLOR_PAIR(WHITE) ^ A_NORMAL);   
  }
  move(11,1);
  printw("----");
  for(std::vector<unsigned int>::size_type k =1 ; k < zaehler.size(); ++k) {
    move(10,k*5);
    printw("|");
    move(11,k*5);
    printw("+----");
    move(12,k*5);
    printw("|");
  }
  move(15,3);
  addstr("Anzahl Tests   : ");
  move(17,3);
  addstr("Anzahl Erfolge : ");
  refresh();

  unsigned int E=0;
  unsigned int max=0;

  getch();

  (void) nodelay(stdscr, 1);
  int ch;

  for(unsigned int k=1; k < n*n*20*2.72; k++) {
    for(std::vector<unsigned int>::size_type i=2; i<30; ++i) 
      key[i]=(rand() % n);

    RC4<n> G(key);
    unsigned int out = G.next();

    
    if (G.S[G.j] == (key[0]+key[1]+1) % n) {
      if ((G.S[G.j] + out) % n == G.i) {
	++E;
      }
    }

    unsigned int x = (n-out) % n;
    ++zaehler[x];
    if (max < zaehler[x]) {
      max = zaehler[x];
      attrset(COLOR_PAIR(RED) ^ A_BOLD);   
    }
    move(12,x*5+1);
    printw("%3d",zaehler[x]);
    attrset(COLOR_PAIR(WHITE) ^ A_NORMAL);   

    move(15,20);
    printw("%4d",k);
    move(17,20);
    printw("%4d",E);

    refresh();

    usleep(5);

    if ((ch = getch()) != ERR) {
      if (ch == 'q') {
	endwin();
	exit(0);
      }
      (void) nodelay(stdscr, 0);
      getch();
      (void) nodelay(stdscr, 1);
    }
  }

  endwin();
  exit(0);

}
