[0CTF/TCTF 2019] zero0des

I had implemented 12 Round DES differential cryptanalysis before(Github Repo, related paper). Although I didn’t check the time complexity accurately, maybe it is smaller than O(2^30).

 

[+] 2020-04-01

 

I find the code..!!

 

DC.cpp

#include "DES.h"
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)
using namespace std;
const int SBOX[8][64] = {
  { 14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1, 3, 10, 10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8, 4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7, 15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13, },
  { 15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14, 9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5, 0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2, 5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9, },
  { 10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10, 1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1, 13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7, 11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12, },
  { 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3, 1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9, 10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8, 15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14, },
  { 2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1, 8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6, 4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13, 15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3, },
  { 12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5, 0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8, 9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10, 7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13, },
  { 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10, 3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6, 1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7, 10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12, },
  { 13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4, 10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2, 7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13, 0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11, }
};
int PC1[56] = { 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 };
const byte CipherOfNULLPlain[8] = { 85, 127, 253, 105, 235, 147, 13, 39 }; // 내가 택한 key가 맞았는지 확인하기 위해 이 값을 참조할 예정
int diff_table[8][64][16];

// diff table을 갱신함
void setDiffTable(void) {
  for (int idx = 0; idx < 8; idx++)
    for (int i = 0; i < 64; i++)
      for (int j = 0; j < 64; j++)
        diff_table[idx][i^j][SBOX[idx][i] ^ SBOX[idx][j]]++;
}

void setRandomKey(byte* KEY) {
  random_device rd;
  mt19937 rng(rd());
  uniform_int_distribution<int> dist1(0, 0xFF);
  for (int i = 0; i < 8; i++)
        KEY[i] = dist1(rng) & 0xFE; // 어차피 각 바이트의 마지막 비트는 parity이므로 0으로 만듬
}
void setRandomPlain(byte* P) {
  random_device rd;
  mt19937 rng(rd());
  uniform_int_distribution<int> dist1(0, 0xFF);
  for (int i = 0; i < 8; i++)
    P[i] = dist1(rng);
}

void setPlainPool(byte* P_original, byte* P, int i) {
  // i의 31-20번째 bit가 P의 (1, 5), (8, 12, 15), (16, 17, 22, 23), (27, 29, 30) 번째 bit에 들어가면 됨.
  for (int i = 0; i < 8; i++)
    P[i] = P_original[i];
  P[0] ^= ((i & 1) << 6); i >>= 1; // i의 마지막 bit를 P의 1번째 bit에 XOR하고 i의 마지막 bit를 제거
  P[0] ^= ((i & 1) << 2); i >>= 1; // P의 5번째 bit   
  P[1] ^= ((i & 1) << 7); i >>= 1; // P의 8번째 bit
  P[1] ^= ((i & 1) << 3); i >>= 1; // P의 12번째 bit
  P[1] ^= (i & 1); i >>= 1; // P의 15번째 bit
  P[2] ^= ((i & 1) << 7); i >>= 1; // P의 16번째 bit
  P[2] ^= ((i & 1) << 6); i >>= 1; // P의 17번째 bit
  P[2] ^= ((i & 1) << 1); i >>= 1; // P의 22번째 bit
  P[2] ^= (i & 1); i >>= 1; // P의 23번째 bit
  P[3] ^= ((i & 1) << 4); i >>= 1; // P의 27번째 bit
  P[3] ^= ((i & 1) << 2); i >>= 1; // P의 29번째 bit
  P[3] ^= ((i & 1) << 1); // P의 30번째 bit
}
void setPlainBar(byte* P, byte* P_bar) { // 19 60 00 00을 P의 right에 XOR
  for (int i = 0; i < 8; i++)
    P_bar[i] = P[i];
  P_bar[4] = P[4] ^ 0x19;
  P_bar[5] = P[5] ^ 0x60;
}
void print_8byte(byte* P) {
  for (int i = 0; i < 8; i++)
    printf("%02X ", P[i]);
  printf("\n");
}

// F 함수의 출력 O에 대해 idx번째 S-box의 출력 결과를 반환 (idx=1 to 8)
// dir = 0 : left 4byte(0 to 3), dir = 1 : right 4byte(4 to 7)
int getSboxOutputBit(byte Intermediate[8], int idx, int dir) {
  byte O[4] = { Intermediate[0 + 4 * dir], Intermediate[1 + 4 * dir], Intermediate[2 + 4 * dir], Intermediate[3 + 4 * dir] };
  switch (idx) {
  case 1: return ((O[1] & 0x80) >> 4) | ((O[2] & 0x80) >> 5) | (O[2] & 0x02) | ((O[3] & 0x02) >> 1);
  case 2: return (O[1] & 0x08) | ((O[3] & 0x10) >> 2) | ((O[0] & 0x40) >> 5) | ((O[2] & 0x40) >> 6);
  case 3: return ((O[2] & 0x01) << 3) | ((O[1] & 0x01) << 2) | ((O[3] & 0x04) >> 1) | ((O[0] & 0x04) >> 2);
  case 4: return ((O[3] & 0x40) >> 3) | ((O[2] & 0x10) >> 2) | ((O[1] & 0x40) >> 5) | ((O[0] & 0x80) >> 7);
  case 5: return ((O[0] & 0x01) << 3) | (O[1] & 0x04) | ((O[3] & 0x80) >> 6) | ((O[0] & 0x20) >> 5);
  case 6: return ((O[0] & 0x10) >> 1) | ((O[3] & 0x08) >> 1) | ((O[1] & 0x20) >> 4) | ((O[2] & 0x20) >> 5);
  case 7: return ((O[3] & 0x01) << 3) | ((O[1] & 0x10) >> 2) | ((O[2] & 0x04) >> 1) | ((O[0] & 0x02) >> 1);
  case 8: return (O[0] & 0x08) | ((O[3] & 0x20) >> 3) | (O[1] & 0x02) | ((O[2] & 0x08) >> 3);
  default: return -1; // unreachable
  }
  return -1; // unreachable
}
// F 함수의 입력 I에 대해 idx번째 S-box의 출력 결과를 반환 (idx=1 to 8)
// dir = 0 : left 4byte(0 to 3), dir = 1 : right 4byte(4 to 7)
int getSboxInputBit(byte Intermediate[8], int idx, int dir) {
  byte I[4] = { Intermediate[0 + 4 * dir], Intermediate[1 + 4 * dir], Intermediate[2 + 4 * dir], Intermediate[3 + 4 * dir] };
  switch (idx) {
  case 1: return ((I[3] & 0x01) << 5) | ((I[0] & 0xf8) >> 3);
  case 2: return ((I[0] & 0x1f) << 1) | ((I[1] & 0x80) >> 7);
  case 3: return ((I[0] & 0x01) << 5) | ((I[1] & 0xf8) >> 3);
  case 4: return ((I[1] & 0x1f) << 1) | ((I[2] & 0x80) >> 7);
  case 5: return ((I[1] & 0x01) << 5) | ((I[2] & 0xf8) >> 3);
  case 6: return ((I[2] & 0x1f) << 1) | ((I[3] & 0x80) >> 7);
  case 7: return ((I[2] & 0x01) << 5) | ((I[3] & 0xf8) >> 3);
  case 8: return ((I[3] & 0x1f) << 1) | ((I[0] & 0x80) >> 7);
  default: return -1; // unreachable
  }
  return -1; // unreachable
}
int ExtractBit() {
  return 0;
}
int** getSurvivingPair(byte P[][8], byte P_bar[][8], byte T[][8], byte T_bar[][8], int POOL_SIZE, int MAX_PAIR) { // surviving pair의 index를 반환
  int** pairlist = (int**)malloc(sizeof(int*) * MAX_PAIR);
  for (int i = 0; i < MAX_PAIR; i++)
    pairlist[i] = (int*)malloc(sizeof(int) * 2);
  for (int i = 0; i < MAX_PAIR; i++) {
    pairlist[i][0] = -1;
    pairlist[i][1] = -1;
  }
  // S1, S2, S3의 output bit (8, 16, 22, 30), (12, 27, 1, 17), (23, 15, 29, 5)을 0으로 만든 32비트 값을 기준으로 정렬해 collision을 찾아낼 예정
  // T, T_bar의 right를 조작하면 됨.
  vector<pair<int, int>> V(POOL_SIZE * 2); // (32비트 값, index)
  for (int i = 0; i < POOL_SIZE; i++) {
    // P의 (1, 5), (8, 12, 15), (16, 17, 22, 23), (27, 29, 30) 번째 bit를 0으로 만들어야함
    // 10111011(BB) 01110110(76) 00111100(3C) 11101001(E9)
    V[i] = { (((T[i][4] << 24) | (T[i][5] << 16) | (T[i][6] << 8) | T[i][7])) & 0xBB763CE9, i };
    V[i + POOL_SIZE] = { (((T_bar[i][4] << 24) | (T_bar[i][5] << 16) | (T_bar[i][6] << 8) | T_bar[i][7])) & 0xBB763CE9, i + POOL_SIZE };
  }
  sort(V.begin(), V.end());
  int pairlist_idx = 0; // 다음번에 삽입할 pairlist의 index
  for (int i = 0; i < 2 * POOL_SIZE - 1; i++) { // V[i], V[i+1]의 first가 동일한지 확인할 예정. first가 동일한게 3개 이상이면 모든 경우를 포함하지 못할 수 있지만 너무나 빈약한 확률로 등장할 일이기 때문에 그냥 무시
    if (V[i].first == V[i + 1].first && V[i].second < POOL_SIZE && V[i + 1].second >= POOL_SIZE) { // V[i]는 T에 속해있고 V[i+1]은 T_bar에 속해있어야하므로 추가된 조건
                                                     // 이제 R1,7,8에서의 S-box의 차분을 살펴보아 실제로 가능한 차분인지 확인. 이 때 확률에 0.0745가 곱해지면서 1.19개의 pair만 살아남음
      // 1. R1에서 S1,S2,S3의 차분이 실제로 가능한 차분인지 diff_table로 확인
      // R1의 input 차분은 00011001(19) 01100000(60) 00000000 00000000 
      // S1의 input 차분 : 000011
      // S2의 input 차분 : 110010
      // S3의 input 차분 : 101100
      int idx0 = V[i].second; // P에 대응되는 index
      int idx1 = V[i + 1].second - POOL_SIZE; // P_bar에 대응되는 index
      byte P_diff[8];
      byte C_diff[8];
      for (int i = 0; i < 8; i++) {
        P_diff[i] = P[idx0][i] ^ P_bar[idx1][i];
        C_diff[i] = T[idx0][i] ^ T_bar[idx1][i];
      }
      if (diff_table[0][0x03][getSboxOutputBit(P_diff, 1, 0)] == 0) // S1의 0x03에 대해 P_diff가 불가능한 차분일 경우
        continue;
      if (diff_table[1][0x32][getSboxOutputBit(P_diff, 2, 0)] == 0) // S2의 0x32에 대해 P_diff가 불가능한 차분일 경우
        continue;
      if (diff_table[2][0x2c][getSboxOutputBit(P_diff, 3, 0)] == 0) // S3의 0x2c에 대해 P_diff가 불가능한 차분일 경우
        continue;
      // 2. R7에서 S1, S2, S3의 차분이 실제로 가능한 차분인지 diff_table로 확인. R7에서 S1, S2, S3의 output 차분은 Cipher의 right
      if (diff_table[0][0x03][getSboxOutputBit(C_diff, 1, 1)] == 0) // S1의 0x03에 대해 P_diff가 불가능한 차분일 경우
        continue;
      if (diff_table[1][0x32][getSboxOutputBit(C_diff, 2, 1)] == 0) // S2의 0x32에 대해 P_diff가 불가능한 차분일 경우
        continue;
      if (diff_table[2][0x2c][getSboxOutputBit(C_diff, 3, 1)] == 0) // S3의 0x2c에 대해 P_diff가 불가능한 차분일 경우
        continue;
      // 3. R8에서 S1-S8의 차분이 실제로 가능한 차분인지 diff_table로 확인
      // C_diff[0~3]에 19(0001 1001) 60(0110 0000) 00 00을 XOR한 것이 F 함수의 출력이다.
      C_diff[0] ^= 0x19;
      C_diff[1] ^= 0x60;
      if (diff_table[0][getSboxInputBit(C_diff, 1, 1)][getSboxOutputBit(C_diff, 1, 0)] == 0) // S1의 input에 대해 P_diff가 불가능한 차분일 경우
        continue;
      if (diff_table[1][getSboxInputBit(C_diff, 2, 1)][getSboxOutputBit(C_diff, 2, 0)] == 0)
        continue;
      if (diff_table[2][getSboxInputBit(C_diff, 3, 1)][getSboxOutputBit(C_diff, 3, 0)] == 0)
        continue;
      if (diff_table[3][getSboxInputBit(C_diff, 4, 1)][getSboxOutputBit(C_diff, 4, 0)] == 0)
        continue;
      if (diff_table[4][getSboxInputBit(C_diff, 5, 1)][getSboxOutputBit(C_diff, 5, 0)] == 0)
        continue;
      if (diff_table[5][getSboxInputBit(C_diff, 6, 1)][getSboxOutputBit(C_diff, 6, 0)] == 0)
        continue;
      if (diff_table[6][getSboxInputBit(C_diff, 7, 1)][getSboxOutputBit(C_diff, 7, 0)] == 0)
        continue;
      if (diff_table[7][getSboxInputBit(C_diff, 8, 1)][getSboxOutputBit(C_diff, 8, 0)] == 0)
        continue;
      // 이 모든 filtering을 통과했다면
      pairlist[pairlist_idx][0] = idx0;
      pairlist[pairlist_idx][1] = idx1;
      pairlist_idx++; // pairlist에 추가
      printf("pairlist_idx : %d\n", pairlist_idx);
      if (pairlist_idx == MAX_PAIR) // 만약 MAX_PAIR개에 도달했으면
        return pairlist; // 그냥 반환
    }
  }
  printf("SurvivingPair done\n");
  return pairlist;
}

bool check_diff_pair(int round, int sbox_idx, int key, int idx0, int idx1, byte P[][8], byte P_bar[][8], byte T[][8], byte T_bar[][8]) {
  if (round == 1) {
    int in1 = getSboxInputBit(P[idx0], sbox_idx, 1);
    int in2 = getSboxInputBit(P_bar[idx1], sbox_idx, 1);
    int out_xor = SBOX[sbox_idx - 1][in1 ^ key] ^ SBOX[sbox_idx - 1][in2 ^ key];
    int exp_out_xor = getSboxOutputBit(P[idx0], sbox_idx, 0) ^ getSboxOutputBit(P_bar[idx1], sbox_idx, 0);
    return out_xor == exp_out_xor;
  }
  else {
    int in1 = getSboxInputBit(T[idx0], sbox_idx, 1);
    int in2 = getSboxInputBit(T_bar[idx1], sbox_idx, 1);
    int out_xor = SBOX[sbox_idx - 1][in1 ^ key] ^ SBOX[sbox_idx - 1][in2 ^ key];
    int exp_out_xor = getSboxOutputBit(T[idx0], sbox_idx, 0) ^ getSboxOutputBit(T_bar[idx1], sbox_idx, 0);
    if (sbox_idx == 4) exp_out_xor ^= 0x2;
    return out_xor == exp_out_xor;
  }

}
const int POOL_SIZE = 4096;
byte P[POOL_SIZE][8]; // P_arbitrary에서 S1, S2, S3의 output bit를 0x000부터 0xFFF까지 바꾼 Plain이 들어감
byte P_bar[POOL_SIZE][8]; // P[i]에 (00 00 00 00 19 60 00 00)을 XOR한 Plain
byte T[POOL_SIZE][8];
byte T_bar[POOL_SIZE][8];
int DC_structure() {
  int cnt = 0;

  int tc = 3;
  printf("enter the integer plz\n");
  scanf("%d", &tc);

  string s = "des_data/"+to_string(tc / 100) + to_string((tc / 10)%10) + to_string(tc % 10)+".txt";
  cout << s << '\n';
  cout << "tc : " << tc << '\n';
  tc++;
  FILE* fp = fopen(s.c_str(), "r");

  for (int i = 0; i < 4096; i++) {
    for (int j = 0; j < 8; j++) fscanf(fp, "%d", &P[i][j]);
    for (int j = 0; j < 8; j++) fscanf(fp, "%d", &T[i][j]);
    for (int j = 0; j < 8; j++) fscanf(fp, "%d", &P_bar[i][j]);
    for (int j = 0; j < 8; j++) fscanf(fp, "%d", &T_bar[i][j]);
  }

  fclose(fp);

    //    setPlainPool(P_arbitrary, P[i], i);
//    setPlainBar(P[i], P_bar[i]);

  //for (int i = 0; i < POOL_SIZE; i++) {
  //  DES(key, P[i], T[i]);
  //  DES(key, P_bar[i], T_bar[i]);
  //}
  // S4-S8의 output bit의 차분이 0이어야 right key일 가능성이 있음
  const int MAX_PAIR = 10;

  int** survivePair = getSurvivingPair(P, P_bar, T, T_bar, POOL_SIZE, MAX_PAIR); // (idx0, idx1) pair가 반환됨
  for (int i = 0; i < MAX_PAIR; i++) {
    int idx0 = survivePair[i][0];
    int idx1 = survivePair[i][1];
    if (idx0 == -1)
      break;

    // print DEBUG
    print_8byte(P[idx0]); printf("\n");
    print_8byte(P_bar[idx1]); printf("\n");
    print_8byte(T[idx0]); printf("\n");
    print_8byte(T_bar[idx1]); printf("\n");
    // R1의 input 차분은 00011001(19) 01100000(60) 00000000 00000000 
    // S1의 input 차분 : 000011
    // S2의 input 차분 : 110010
    // S3의 input 차분 : 101100
    // 해당하는 pair에 대응되는 key를 찾아 right key인지 확인할 것임
    bool keybit[56] = { 0, }; // PC1을 거친 상태의 키
    long long totcand = 0;
    // Round1 S3 부터 시작. (23 19 12 4 26 8)
    for (int r1s3 = 0; r1s3 < 64; r1s3++) {
      keybit[23] = (r1s3 & 0x20) >> 5;
      keybit[19] = (r1s3 & 0x10) >> 4;
      keybit[12] = (r1s3 & 0x08) >> 3;
      keybit[4] = (r1s3 & 0x04) >> 2;
      keybit[26] = (r1s3 & 0x02) >> 1;
      keybit[8] = r1s3 & 0x01;
      int key = r1s3;

      if (!check_diff_pair(1,3,key,idx0,idx1,P,P_bar,T,T_bar))
        continue;
      //output XOR이 일치한다면 이제 R8 S4로 넘어감.(1 20 12 5 26 15) 1 5 15 20을 정해야함
      for (int r8s4 = 0; r8s4 < 16; r8s4++) {
        keybit[1] = (r8s4 & 0x08) >> 3;
        keybit[5] = (r8s4 & 0x04) >> 2;
        keybit[15] = (r8s4 & 0x02) >> 1;
        keybit[20] = r8s4 & 0x01;
        int key = (int)keybit[1] << 5 | (int)keybit[20] << 4 | (int)keybit[12] << 3 | (int)keybit[5] << 2 | (int)keybit[26] << 1 | (int)keybit[15];
        if (!check_diff_pair(8, 3, key, idx0, idx1, P, P_bar, T, T_bar))
          continue;
        int R8S4_key = key;
        int R8S4_output1 = SBOX[3][getSboxInputBit(T[idx0], 4, 1) ^ key];

        //ROUND1 S1(14 17 11 24 1 5), 14 24 17 11을 정해야됨
        for (int r1s1 = 0; r1s1 < 16; r1s1++) {
          keybit[14] = (r1s1 & 0x08) >> 3;
          keybit[24] = (r1s1 & 0x04) >> 2;
          keybit[17] = (r1s1 & 0x02) >> 1;
          keybit[11] = r1s1 & 0x01;
          int key = (int)keybit[14] << 5 | (int)keybit[17] << 4 | (int)keybit[11] << 3 | (int)keybit[24] << 2 | (int)keybit[1] << 1 | (int)keybit[5];
          if (!check_diff_pair(1, 1, key, idx0, idx1, P, P_bar, T, T_bar))
            continue;

          //ROUND8 S2(16 13 0 19 6 23) 0 6 16 13를 정해야함
          for (int r8s2 = 0; r8s2 < 16; r8s2++) {
            keybit[0] = (r8s2 & 0x08) >> 3;
            keybit[6] = (r8s2 & 0x04) >> 2;
            keybit[16] = (r8s2 & 0x02) >> 1;
            keybit[13] = r8s2 & 0x01;
            int key = (int)keybit[16] << 5 | (int)keybit[13] << 4 | (int)keybit[0] << 3 | (int)keybit[19] << 2 | (int)keybit[6] << 1 | (int)keybit[23];
            if (!check_diff_pair(8, 2, key, idx0, idx1, P, P_bar, T, T_bar))
              continue;
            int R8S2_key = key;
            int R8S2_output1 = SBOX[1][getSboxInputBit(T[idx0], 2, 1) ^ key];

            //ROUND1 S4(16 7 27 20 13 2), 2 27 7을 정해야됨
            for (int r1s4 = 0; r1s4 < 8; r1s4++) {
              keybit[2] = (r1s4 & 0x04) >> 2;
              keybit[27] = (r1s4 & 0x02) >> 1;
              keybit[7] = r1s4 & 0x01;
              int key = (int)keybit[16] << 5 | (int)keybit[7] << 4 | (int)keybit[27] << 3 | (int)keybit[20] << 2 | (int)keybit[13] << 1 | (int)keybit[2];
              if (!check_diff_pair(1, 4, key, idx0, idx1, P, P_bar, T, T_bar))
                continue;

              //ROUND1 S2(3 0 15 6 21 10), 21 3 10을 정해야됨
              for (int r1s2 = 0; r1s2 < 8; r1s2++) {
                keybit[21] = (r1s2 & 0x04) >> 2;
                keybit[3] = (r1s2 & 0x02) >> 1;
                keybit[10] = r1s2 & 0x01;
                int key = (int)keybit[3] << 5 | (int)keybit[0] << 4 | (int)keybit[15] << 3 | (int)keybit[6] << 2 | (int)keybit[21] << 1 | (int)keybit[10];
                if (!check_diff_pair(1, 2, key, idx0, idx1, P, P_bar, T, T_bar))
                  continue;

                //ROUND8 S1(27 2 24 9 14 18), 9 18을 정해야됨
                for (int r8s1 = 0; r8s1 < 4; r8s1++) {
                  keybit[9] = (r8s1 & 0x02) >> 1;
                  keybit[18] = r8s1 & 0x01;
                  int key = (int)keybit[27] << 5 | (int)keybit[2] << 4 | (int)keybit[24] << 3 | (int)keybit[9] << 2 | (int)keybit[14] << 1 | (int)keybit[18];
                  if (!check_diff_pair(8, 1, key, idx0, idx1, P, P_bar, T, T_bar))
                    continue;
                  int R8S1_key = key;
                  int R8S1_output1 = SBOX[0][getSboxInputBit(T[idx0], 1, 1) ^ key];
                  //ROUND8 S3(8 4 25 17 11 21), 25을 정해야됨
                  for (int r8s3 = 0; r8s3 < 2; r8s3++) {
                    keybit[25] = r8s3;
                    int key = (int)keybit[8] << 5 | (int)keybit[4] << 4 | (int)keybit[25] << 3 | (int)keybit[17] << 2 | (int)keybit[11] << 1 | (int)keybit[21];
                    if (!check_diff_pair(8, 3, key, idx0, idx1, P, P_bar, T, T_bar))
                      continue;
                    int R8S3_key = key;
                    int R8S3_output1 = SBOX[2][getSboxInputBit(T[idx0], 3, 1) ^ key];
                    // 22번째 비트가 어디에도 쓰이지 않아 임의로 잡음
                    for (int freeval = 0; freeval < 2; freeval++) {
                      keybit[22] = freeval;

                      // 현재 left key는 모두 복원에 성공함. right key를 찾자.
                      // 여기까지 통과했으면 일단 expected XOR은 다 제대로 나옴. left key는 다 복원한 상태.
                      // 이제 right key를 찾아낼 것임
                      // R7S1_input1 ^ R7S1_input2 = 0x03
                      // 내가 P[idx0]에 대한 input value를 정하면 P_bar[idx1]에 대한 input value또한 정해지고, S1-S4에 대한 key는 아니까 output value가 기대한 XOR값이 나오는지 확인 가능
                      // Permutation S1 : 24 15 6 19 20 28, 24 19 20 28 값을 임의로 정해야 함

                      bool I8_input1[32] = { 0, };
                      bool I8_input2[32] = { 0, };
                      for (int r7s1 = 0; r7s1 < 16; r7s1++) {
                        int R7S1_key = (int)keybit[25] << 5 | (int)keybit[0] << 4 | (int)keybit[22] << 3 | (int)keybit[7] << 2 | (int)keybit[12] << 1 | (int)keybit[16];
                        I8_input1[24] = (r7s1 & 0x08) >> 3;
                        int i2 = R8S4_output1 & 0x01;
                        int i3 = (R8S2_output1 & 0x02) >> 1;
                        I8_input1[19] = (r7s1 & 0x04) >> 2;
                        I8_input1[20] = (r7s1 & 0x02) >> 1;
                        I8_input1[28] = r7s1 & 0x01;
                        int R7S1_input1 = ((int)I8_input1[24] << 5 | i2 << 4 | i3 << 3 | (int)I8_input1[19] << 2 | (int)I8_input1[20] << 1 | (int)I8_input1[28]) ^ getSboxInputBit(T[idx0], 1, 0);
                        int R7S1_input2 = R7S1_input1 ^ 0x03;
                        int R7S1_output1 = SBOX[0][R7S1_input1 ^ R7S1_key];
                        int R7S1_output2 = SBOX[0][R7S1_input2 ^ R7S1_key];
                        int R7S1_output_XOR = R7S1_output1 ^ R7S1_output2;
                        int expected_R7S1_output_XOR = getSboxOutputBit(T[idx0], 1, 1) ^ getSboxOutputBit(T_bar[idx1], 1, 1);
                        if (R7S1_output_XOR != expected_R7S1_output_XOR) {
                          continue;
                        }
                        int t = R7S1_input2 ^ getSboxInputBit(T_bar[idx1], 1, 0);
                        I8_input2[24] = (t & 0x20) >> 5;
                        I8_input2[19] = (t & 0x04) >> 2;
                        I8_input2[20] = (t & 0x02) >> 1;
                        I8_input2[28] = t & 0x01;

                        // Round7 S2에서 input XOR은 0x32이다.
                        // Permutation S2 : 20 28 11 27 16 0, 27 16 값을 임의로 정해야 함
                        for (int r7s2 = 0; r7s2 < 4; r7s2++) {
                          int R7S2_key = (int)keybit[14] << 5 | (int)keybit[11] << 4 | (int)keybit[26] << 3 | (int)keybit[17] << 2 | (int)keybit[4] << 1 | (int)keybit[21];
                          int i3 = R8S3_output1 & 0x01;
                          I8_input1[27] = (r7s2 & 0x02) >> 1;
                          I8_input1[16] = r7s2 & 0x01;
                          int i6 = (R8S1_output1 & 0x08) >> 3;
                          int R7S2_input1 = ((int)I8_input1[20] << 5 | (int)I8_input1[28] << 4 | i3 << 3 | (int)I8_input1[27] << 2 | (int)I8_input1[16] << 1 | i6) ^ getSboxInputBit(T[idx0], 2, 0);
                          int R7S2_input2 = R7S2_input1 ^ 0x32;
                          int R7S2_output1 = SBOX[1][R7S2_input1 ^ R7S2_key];
                          int R7S2_output2 = SBOX[1][R7S2_input2 ^ R7S2_key];
                          int R7S2_output_XOR = R7S2_output1 ^ R7S2_output2;
                          int expected_R7S2_output_XOR = getSboxOutputBit(T[idx0], 2, 1) ^ getSboxOutputBit(T_bar[idx1], 2, 1);
                          if (R7S2_output_XOR != expected_R7S2_output_XOR)
                            continue;
                          int t = R7S2_input2 ^ getSboxInputBit(T_bar[idx1], 2, 0);
                          I8_input2[27] = (t & 0x04) >> 2;
                          I8_input2[16] = (t & 0x02) >> 1;

                          // Round7 S3에서 input XOR은 0x2c이다.
                          // Permutation S3 : 16 0 14 22 25 4, 22 25 값을 임의로 정해야 함
                          for (int r7s3 = 0; r7s3 < 4; r7s3++) {
                            int R7S3_key = (int)keybit[6] << 5 | (int)keybit[2] << 4 | (int)keybit[23] << 3 | (int)keybit[15] << 2 | (int)keybit[9] << 1 | (int)keybit[19];
                            int i2 = (R8S1_output1 & 0x08) >> 3;
                            int i3 = (R8S4_output1 & 0x02) >> 1;
                            I8_input1[22] = (r7s3 & 0x02) >> 1;
                            I8_input1[25] = r7s3 & 0x01;
                            int i6 = (R8S2_output1 & 0x08) >> 3;
                            int R7S3_input1 = ((int)I8_input1[16] << 5 | i2 << 4 | i3 << 3 | (int)I8_input1[22] << 2 | (int)I8_input1[25] << 1 | i6) ^ getSboxInputBit(T[idx0], 3, 0);
                            int R7S3_input2 = R7S3_input1 ^ 0x2c;
                            int R7S3_output1 = SBOX[2][R7S3_input1 ^ R7S3_key];
                            int R7S3_output2 = SBOX[2][R7S3_input2 ^ R7S3_key];
                            int R7S3_output_XOR = R7S3_output1 ^ R7S3_output2;
                            int expected_R7S3_output_XOR = getSboxOutputBit(T[idx0], 3, 1) ^ getSboxOutputBit(T_bar[idx1], 3, 1);
                            if (R7S3_output_XOR != expected_R7S3_output_XOR)
                              continue;
                            int t = R7S3_input2 ^ getSboxInputBit(T_bar[idx1], 3, 0);
                            I8_input2[22] = (t & 0x04) >> 2;
                            I8_input2[25] = (t & 0x02) >> 1;

                            // Round8 S5에서 keybit(54 37 44 50 32 40)을 택하고 output value를 충족하는지 확인
                            // output bit는 16 17 18 19이고 16 19는 값을 알고있음
                            for (int r8s5 = 0; r8s5 < 64; r8s5++) {
                              keybit[54] = (r8s5 & 0x20) >> 5;
                              keybit[37] = (r8s5 & 0x10) >> 4;
                              keybit[44] = (r8s5 & 0x08) >> 3;
                              keybit[50] = (r8s5 & 0x04) >> 2;
                              keybit[32] = (r8s5 & 0x02) >> 1;
                              keybit[40] = r8s5 & 0x01;
                              int R8S5_key = r8s5;
                              int R8S5_input1 = getSboxInputBit(T[idx0], 5, 1);
                              int R8S5_input2 = getSboxInputBit(T_bar[idx1], 5, 1);
                              if ((SBOX[4][R8S5_input1 ^ R8S5_key] & 0x09) != ((int)I8_input1[16] << 3 | (int)I8_input1[19])) // 가운데 두 bit는 unknown이므로.
                                continue;
                              if ((SBOX[4][R8S5_input2 ^ R8S5_key] & 0x09) != ((int)I8_input2[16] << 3 | (int)I8_input2[19])) // 가운데 두 bit는 unknown이므로.
                                continue;
                              int t = SBOX[4][R8S5_input1 ^ R8S5_key];
                              I8_input1[17] = (t & 0x04) >> 2;
                              I8_input1[18] = (t & 0x02) >> 1;
                              t = SBOX[4][R8S5_input2 ^ R8S5_key];
                              I8_input2[17] = (t & 0x04) >> 2;
                              I8_input2[18] = (t & 0x02) >> 1;

                              // Round8 S6에서 keybit(43 53 36 30 46 33)을 택하고 output value를 충족하는지 확인
                              // output bit는 20 21 22 23이고 20 22은 값을 알고있음 
                              for (int r8s6 = 0; r8s6 < 64; r8s6++) {
                                keybit[43] = (r8s6 & 0x20) >> 5;
                                keybit[53] = (r8s6 & 0x10) >> 4;
                                keybit[36] = (r8s6 & 0x08) >> 3;
                                keybit[30] = (r8s6 & 0x04) >> 2;
                                keybit[46] = (r8s6 & 0x02) >> 1;
                                keybit[33] = r8s6 & 0x01;
                                int R8S6_key = r8s6;
                                int R8S6_input1 = getSboxInputBit(T[idx0], 6, 1);
                                int R8S6_input2 = getSboxInputBit(T_bar[idx1], 6, 1);
                                if ((SBOX[5][R8S6_input1 ^ R8S6_key] & 0x0A) != ((int)I8_input1[20] << 3 | (int)I8_input1[22] << 1)) // 가운데 두 bit는 unknown이므로.
                                  continue;
                                if ((SBOX[5][R8S6_input2 ^ R8S6_key] & 0x0A) != ((int)I8_input2[20] << 3 | (int)I8_input2[22] << 1)) // 가운데 두 bit는 unknown이므로.
                                  continue;
                                int t = SBOX[5][R8S6_input1 ^ R8S6_key];
                                I8_input1[21] = (t & 0x04) >> 2;
                                I8_input1[23] = t & 0x01;
                                t = SBOX[5][R8S6_input2 ^ R8S6_key];
                                I8_input2[21] = (t & 0x04) >> 2;
                                I8_input2[23] = t & 0x01;

                                // Round8 S7에서 keybit(29 34 52 41 47 38)을 택하고 output value를 충족하는지 확인
                                // output bit는 24 25 26 27이고 24 25 27은 값을 알고있음 
                                for (int r8s7 = 0; r8s7 < 64; r8s7++) {
                                  keybit[29] = (r8s7 & 0x20) >> 5;
                                  keybit[34] = (r8s7 & 0x10) >> 4;
                                  keybit[52] = (r8s7 & 0x08) >> 3;
                                  keybit[41] = (r8s7 & 0x04) >> 2;
                                  keybit[47] = (r8s7 & 0x02) >> 1;
                                  keybit[38] = r8s7 & 0x01;
                                  int R8S7_key = r8s7;
                                  int R8S7_input1 = getSboxInputBit(T[idx0], 7, 1);
                                  int R8S7_input2 = getSboxInputBit(T_bar[idx1], 7, 1);
                                  if ((SBOX[6][R8S7_input1 ^ R8S7_key] & 0x0D) != ((int)I8_input1[24] << 3 | (int)I8_input1[25] << 2 | (int)I8_input1[27])) // 가운데 한 bit는 unknown이므로.
                                    continue;
                                  if ((SBOX[6][R8S7_input2 ^ R8S7_key] & 0x0D) != ((int)I8_input2[24] << 3 | (int)I8_input2[25] << 2 | (int)I8_input2[27])) // 가운데 한 bit는 unknown이므로.
                                    continue;
                                  int t = SBOX[6][R8S7_input1 ^ R8S7_key];
                                  I8_input1[26] = (t & 0x02) >> 1;
                                  t = SBOX[6][R8S7_input2 ^ R8S7_key];
                                  I8_input2[26] = (t & 0x02) >> 1;

                                  // Round8 S8에서 keybit(31 55 35 49 42 45)을 택하고 output value를 충족하는지 확인
                                  // output bit는 28 29 30 31이고 28은 값을 알고있음 
                                  for (int r8s8 = 0; r8s8 < 64; r8s8++) {
                                    keybit[31] = (r8s8 & 0x20) >> 5;
                                    keybit[55] = (r8s8 & 0x10) >> 4;
                                    keybit[35] = (r8s8 & 0x08) >> 3;
                                    keybit[49] = (r8s8 & 0x04) >> 2;
                                    keybit[42] = (r8s8 & 0x02) >> 1;
                                    keybit[45] = r8s8 & 0x01;
                                    int R8S8_key = r8s8;
                                    int R8S8_input1 = getSboxInputBit(T[idx0], 8, 1);
                                    int R8S8_input2 = getSboxInputBit(T_bar[idx1], 8, 1);
                                    if ((SBOX[7][R8S8_input1 ^ R8S8_key] & 0x08) != ((int)I8_input1[28] << 3)) // 가운데 한 bit는 unknown이므로.
                                      continue;
                                    if ((SBOX[7][R8S8_input2 ^ R8S8_key] & 0x08) != ((int)I8_input2[28] << 3)) // 가운데 한 bit는 unknown이므로.
                                      continue;
                                    int t = SBOX[7][R8S8_input1 ^ R8S8_key];
                                    I8_input1[29] = (t & 0x04) >> 2;
                                    I8_input1[30] = (t & 0x02) >> 1;
                                    I8_input1[31] = t & 0x01;
                                    t = SBOX[7][R8S8_input2 ^ R8S8_key];
                                    I8_input2[29] = (t & 0x04) >> 2;
                                    I8_input2[30] = (t & 0x02) >> 1;
                                    I8_input2[31] = t & 0x01;
                                    int keylist[4] = { R8S1_key, R8S2_key, R8S3_key, R8S4_key };
                                    for (int i = 0; i < 4; i++) {
                                      int t = SBOX[i][getSboxInputBit(T[idx0], i + 1, 1) ^ keylist[i]];
                                      I8_input1[4 * i] = (t & 0x08) >> 3;
                                      I8_input1[4 * i + 1] = (t & 0x04) >> 2;
                                      I8_input1[4 * i + 2] = (t & 0x02) >> 1;
                                      I8_input1[4 * i + 3] = t & 0x01;
                                    }
                                    for (int i = 0; i < 4; i++) {
                                      int t = SBOX[i][getSboxInputBit(T_bar[idx1], i + 1, 1) ^ keylist[i]];
                                      I8_input2[4 * i] = (t & 0x08) >> 3;
                                      I8_input2[4 * i + 1] = (t & 0x04) >> 2;
                                      I8_input2[4 * i + 2] = (t & 0x02) >> 1;
                                      I8_input2[4 * i + 3] = t & 0x01;
                                    }

                                    // 현재 R8를 통해 I8_input1, I8_input2를 전부 복원했고 key는 28 39 48 51 bit를 제외하고 전부 복원했다.
                                    // 이제 4bit는 전수조사를 통해 right key인지 알아낼 것이다.
                                    // right key인지 알아내는 방법은 CPA 환경이므로 그냥 실제로 암호화를 한 번 수행하기만 하면 된다.
                                    for (int key_brute = 0; key_brute < 16; key_brute++) {
                                      keybit[28] = (key_brute & 0x08) >> 3;
                                      keybit[39] = (key_brute & 0x04) >> 2;
                                      keybit[48] = (key_brute & 0x02) >> 1;
                                      keybit[51] = key_brute & 0x01;
                                      totcand++;
                                      if (totcand % 10000000 == 0) {
                                        printf("totcand : %lld\n", totcand);
                                      }
                                      byte candidateKey[8] = { 0, };
                                      bool tempKeybit[64] = { 0, };
                                      for (int i = 0; i < 56; i++)
                                        tempKeybit[PC1[i]] = keybit[i];
                                      for (int i = 0; i < 8; i++)
                                        for (int j = 0; j <= 6; j++)
                                          candidateKey[i] = (candidateKey[i] | tempKeybit[8 * i + j]) << 1;
                                      unsigned int candkey[32];
                                      des_key_setup(candidateKey, candkey);
                                      byte NULLplain[8] = { 0, };
                                      byte C[8] = { 73, 242, 190, 240, 182, 31, 150, 7 };
                                      DES(candkey, NULLplain, C);
                                      bool isRightKey = true;
                                      for (int i = 0; i < 8; i++) {
                                        //printf("%d %d\n", (int)C[i], (int)CipherOfNULLPlain[i]);
                                        if (C[i] != CipherOfNULLPlain[i]) {
                                          isRightKey = false;
                                          break;
                                        }
                                      }
                                      if (isRightKey) {
                                        printf("Congratz!!! suggested key : ");
                                        print_8byte(candidateKey);
                                        printf("Plain1 : ");
                                        print_8byte(P[idx0]);
                                        printf("Plain2 : ");
                                        print_8byte(P_bar[idx1]);
                                        int t;
                                        scanf("%d", &t);
                                        return true;
                                      }
                                    }
                                  }
                                }
                              }
                            }
                          }
                        }
                      }

                    }
                  }
                }           
              }
            }
          }
        }
      }     
    }
  }
  for (int i = 0; i < MAX_PAIR; i++)
    free(survivePair[i]);
  free(survivePair);
  return false;
}
void printKey(byte* KEY) {
  printf("KEY : ");
  for (int i = 0; i < 8; i++)
    printf("%02X ", KEY[i]);
  printf("\n");
}
int main(void)
{

  printf("Differential Cryptanalysis on DES\n");
  //  byte KEY[8] = { 0xA2, 0x16, 0x40, 0xC2, 0x4E, 0x18, 0x54, 0x06};
  byte KEY[8] = { 0x75, 0x28, 0x78, 0x39, 0x74, 0x93, 0xCB, 0x70 };
  unsigned int key[32];
  //printf("Set random key.. ");
  //setRandomKey(KEY); // CPA 환경에서 이 KEY를 찾아내는 것이 목표임
  //printKey(KEY);
  //des_key_setup(KEY, key);
  //for (int i = 0; i < 16; i++) {
  //  printf("%08x %08x\n", key[2 * i], key[2 * i + 1]);
  //}

/*
  byte P1[8] = { 0x2C, 0x2F, 0x45, 0xE3, 0x26, 0xBC, 0xF9, 0xA1 };  
  byte C1[8] = { 0, };
  printf("P1 : ");
  print_8byte(P1);
  DES(key, P1, C1);
  printf("C1 : ");
  print_8byte(C1);
  printf("\n\n");
  byte P2[8] = { 0x2C, 0x2E, 0x84, 0xE5, 0x3F, 0xDC, 0xF9, 0xA1 };
  byte C2[8] = { 0, };
  printf("P2 : ");
  print_8byte(P2);
  DES(key, P2, C2);
  printf("C2 : ");
  print_8byte(C2);


  return 0;*/
  setDiffTable();
  byte NullPlain[8] = { 0,};
  //DES(key, NullPlain, CipherOfNULLPlain);
  //printf("Cipher of NULL Plaintext : ");
  //print_8byte(CipherOfNULLPlain);

//    scanf("%hhd", &CipherOfNULLPlain[i]);
//  for (int i = 0; i < 8; i++)
//    printf("%hhd ", CipherOfNULLPlain[i]);

  // 10000개의 structure에 400개 pair
  for (int T = 1; ; T++) {

    printf("=============%d-th structure try==============\n", T);

    if (DC_structure()) {
      printf("\n\nfind key in %dth structure try\n", T);
      break;
    }
  }
}

DES.h

#include <stdio.h>
#include <windows.h>
#include <time.h>
#include <random>
#include <stdlib.h>
#include <algorithm>
#include <bits/stdc++.h>
#define _CRT_SECURE_NO_WARNINGS
void DES(unsigned int* key, byte* text, byte* C);
void des_key_setup(byte* key, unsigned int* ek);

DES.cpp

// IP, FP는 제거
#include "DES.h"
const int SBOX[8][64] = {
  { 14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1, 3, 10, 10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8, 4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7, 15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13, },
  { 15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14, 9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5, 0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2, 5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9, },
  { 10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10, 1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1, 13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7, 11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12, },
  { 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3, 1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9, 10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8, 15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14, },
  { 2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1, 8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6, 4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13, 15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3, },
  { 12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5, 0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8, 9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10, 7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13, },
  { 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10, 3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6, 1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7, 10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12, },
  { 13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4, 10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2, 7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13, 0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11, } };
static int keysh[] =
{
  1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1,
};
const unsigned int SB1[64] = { 0x00808200,0x00000000,0x00008000,0x00808202,0x00808002,0x00008202,0x00000002,0x00008000,
0x00000200,0x00808200,0x00808202,0x00000200,0x00800202,0x00808002,0x00800000,0x00000002,
0x00000202,0x00800200,0x00800200,0x00008200,0x00008200,0x00808000,0x00808000,0x00800202,
0x00008002,0x00800002,0x00800002,0x00008002,0x00000000,0x00000202,0x00008202,0x00800000,
0x00008000,0x00808202,0x00000002,0x00808000,0x00808200,0x00800000,0x00800000,0x00000200,
0x00808002,0x00008000,0x00008200,0x00800002,0x00000200,0x00000002,0x00800202,0x00008202,
0x00808202,0x00008002,0x00808000,0x00800202,0x00800002,0x00000202,0x00008202,0x00808200,
0x00000202,0x00800200,0x00800200,0x00000000,0x00008002,0x00008200,0x00000000,0x00808002 };
const unsigned int SB2[64] = { 0x40084010,0x40004000,0x00004000,0x00084010,0x00080000,0x00000010,0x40080010,0x40004010,
0x40000010,0x40084010,0x40084000,0x40000000,0x40004000,0x00080000,0x00000010,0x40080010,
0x00084000,0x00080010,0x40004010,0x00000000,0x40000000,0x00004000,0x00084010,0x40080000,
0x00080010,0x40000010,0x00000000,0x00084000,0x00004010,0x40084000,0x40080000,0x00004010,
0x00000000,0x00084010,0x40080010,0x00080000,0x40004010,0x40080000,0x40084000,0x00004000,
0x40080000,0x40004000,0x00000010,0x40084010,0x00084010,0x00000010,0x00004000,0x40000000,
0x00004010,0x40084000,0x00080000,0x40000010,0x00080010,0x40004010,0x40000010,0x00080010,
0x00084000,0x00000000,0x40004000,0x00004010,0x40000000,0x40080010,0x40084010,0x00084000 };
const unsigned int SB3[64] = { 0x00000104,0x04010100,0x00000000,0x04010004,0x04000100,0x00000000,0x00010104,0x04000100,
0x00010004,0x04000004,0x04000004,0x00010000,0x04010104,0x00010004,0x04010000,0x00000104,
0x04000000,0x00000004,0x04010100,0x00000100,0x00010100,0x04010000,0x04010004,0x00010104,
0x04000104,0x00010100,0x00010000,0x04000104,0x00000004,0x04010104,0x00000100,0x04000000,
0x04010100,0x04000000,0x00010004,0x00000104,0x00010000,0x04010100,0x04000100,0x00000000,
0x00000100,0x00010004,0x04010104,0x04000100,0x04000004,0x00000100,0x00000000,0x04010004,
0x04000104,0x00010000,0x04000000,0x04010104,0x00000004,0x00010104,0x00010100,0x04000004,
0x04010000,0x04000104,0x00000104,0x04010000,0x00010104,0x00000004,0x04010004,0x00010100 };
const unsigned int SB4[64] = { 0x80401000,0x80001040,0x80001040,0x00000040,0x00401040,0x80400040,0x80400000,0x80001000,
0x00000000,0x00401000,0x00401000,0x80401040,0x80000040,0x00000000,0x00400040,0x80400000,
0x80000000,0x00001000,0x00400000,0x80401000,0x00000040,0x00400000,0x80001000,0x00001040,
0x80400040,0x80000000,0x00001040,0x00400040,0x00001000,0x00401040,0x80401040,0x80000040,
0x00400040,0x80400000,0x00401000,0x80401040,0x80000040,0x00000000,0x00000000,0x00401000,
0x00001040,0x00400040,0x80400040,0x80000000,0x80401000,0x80001040,0x80001040,0x00000040,
0x80401040,0x80000040,0x80000000,0x00001000,0x80400000,0x80001000,0x00401040,0x80400040,
0x80001000,0x00001040,0x00400000,0x80401000,0x00000040,0x00400000,0x00001000,0x00401040 };
const unsigned int SB5[64] = { 0x00000080,0x01040080,0x01040000,0x21000080,0x00040000,0x00000080,0x20000000,0x01040000,
0x20040080,0x00040000,0x01000080,0x20040080,0x21000080,0x21040000,0x00040080,0x20000000,
0x01000000,0x20040000,0x20040000,0x00000000,0x20000080,0x21040080,0x21040080,0x01000080,
0x21040000,0x20000080,0x00000000,0x21000000,0x01040080,0x01000000,0x21000000,0x00040080,
0x00040000,0x21000080,0x00000080,0x01000000,0x20000000,0x01040000,0x21000080,0x20040080,
0x01000080,0x20000000,0x21040000,0x01040080,0x20040080,0x00000080,0x01000000,0x21040000,
0x21040080,0x00040080,0x21000000,0x21040080,0x01040000,0x00000000,0x20040000,0x21000000,
0x00040080,0x01000080,0x20000080,0x00040000,0x00000000,0x20040000,0x01040080,0x20000080 };
const unsigned int SB6[64] = { 0x10000008,0x10200000,0x00002000,0x10202008,0x10200000,0x00000008,0x10202008,0x00200000,
0x10002000,0x00202008,0x00200000,0x10000008,0x00200008,0x10002000,0x10000000,0x00002008,
0x00000000,0x00200008,0x10002008,0x00002000,0x00202000,0x10002008,0x00000008,0x10200008,
0x10200008,0x00000000,0x00202008,0x10202000,0x00002008,0x00202000,0x10202000,0x10000000,
0x10002000,0x00000008,0x10200008,0x00202000,0x10202008,0x00200000,0x00002008,0x10000008,
0x00200000,0x10002000,0x10000000,0x00002008,0x10000008,0x10202008,0x00202000,0x10200000,
0x00202008,0x10202000,0x00000000,0x10200008,0x00000008,0x00002000,0x10200000,0x00202008,
0x00002000,0x00200008,0x10002008,0x00000000,0x10202000,0x10000000,0x00200008,0x10002008 };
const unsigned int SB7[64] = { 0x00100000,0x02100001,0x02000401,0x00000000,0x00000400,0x02000401,0x00100401,0x02100400,
0x02100401,0x00100000,0x00000000,0x02000001,0x00000001,0x02000000,0x02100001,0x00000401,
0x02000400,0x00100401,0x00100001,0x02000400,0x02000001,0x02100000,0x02100400,0x00100001,
0x02100000,0x00000400,0x00000401,0x02100401,0x00100400,0x00000001,0x02000000,0x00100400,
0x02000000,0x00100400,0x00100000,0x02000401,0x02000401,0x02100001,0x02100001,0x00000001,
0x00100001,0x02000000,0x02000400,0x00100000,0x02100400,0x00000401,0x00100401,0x02100400,
0x00000401,0x02000001,0x02100401,0x02100000,0x00100400,0x00000000,0x00000001,0x02100401,
0x00000000,0x00100401,0x02100000,0x00000400,0x02000001,0x02000400,0x00000400,0x00100001 };
const unsigned int SB8[64] = { 0x08000820,0x00000800,0x00020000,0x08020820,0x08000000,0x08000820,0x00000020,0x08000000,
0x00020020,0x08020000,0x08020820,0x00020800,0x08020800,0x00020820,0x00000800,0x00000020,
0x08020000,0x08000020,0x08000800,0x00000820,0x00020800,0x00020020,0x08020020,0x08020800,
0x00000820,0x00000000,0x00000000,0x08020020,0x08000020,0x08000800,0x00020820,0x00020000,
0x00020820,0x00020000,0x08020800,0x00000800,0x00000020,0x08020020,0x00000800,0x00020820,
0x08000800,0x00000020,0x08000020,0x08020000,0x08020020,0x08000000,0x00020000,0x08000820,
0x00000000,0x08020820,0x00020020,0x08000020,0x08020000,0x08000800,0x08000820,0x00000000,
0x08020820,0x00020800,0x00020800,0x00000820,0x00000820,0x00020020,0x08000000,0x08020800 };
static unsigned int comptab[] = {

  0x000000,0x010000,0x000008,0x010008,0x000080,0x010080,0x000088,0x010088,
  0x000000,0x010000,0x000008,0x010008,0x000080,0x010080,0x000088,0x010088,

  0x000000,0x100000,0x000800,0x100800,0x000000,0x100000,0x000800,0x100800,
  0x002000,0x102000,0x002800,0x102800,0x002000,0x102000,0x002800,0x102800,

  0x000000,0x000004,0x000400,0x000404,0x000000,0x000004,0x000400,0x000404,
  0x400000,0x400004,0x400400,0x400404,0x400000,0x400004,0x400400,0x400404,

  0x000000,0x000020,0x008000,0x008020,0x800000,0x800020,0x808000,0x808020,
  0x000002,0x000022,0x008002,0x008022,0x800002,0x800022,0x808002,0x808022,

  0x000000,0x000200,0x200000,0x200200,0x001000,0x001200,0x201000,0x201200,
  0x000000,0x000200,0x200000,0x200200,0x001000,0x001200,0x201000,0x201200,

  0x000000,0x000040,0x000010,0x000050,0x004000,0x004040,0x004010,0x004050,
  0x040000,0x040040,0x040010,0x040050,0x044000,0x044040,0x044010,0x044050,

  0x000000,0x000100,0x020000,0x020100,0x000001,0x000101,0x020001,0x020101,
  0x080000,0x080100,0x0a0000,0x0a0100,0x080001,0x080101,0x0a0001,0x0a0101,

  0x000000,0x000100,0x040000,0x040100,0x000000,0x000100,0x040000,0x040100,
  0x000040,0x000140,0x040040,0x040140,0x000040,0x000140,0x040040,0x040140,

  0x000000,0x400000,0x008000,0x408000,0x000008,0x400008,0x008008,0x408008,
  0x000400,0x400400,0x008400,0x408400,0x000408,0x400408,0x008408,0x408408,

  0x000000,0x001000,0x080000,0x081000,0x000020,0x001020,0x080020,0x081020,
  0x004000,0x005000,0x084000,0x085000,0x004020,0x005020,0x084020,0x085020,

  0x000000,0x000800,0x000000,0x000800,0x000010,0x000810,0x000010,0x000810,
  0x800000,0x800800,0x800000,0x800800,0x800010,0x800810,0x800010,0x800810,

  0x000000,0x010000,0x000200,0x010200,0x000000,0x010000,0x000200,0x010200,
  0x100000,0x110000,0x100200,0x110200,0x100000,0x110000,0x100200,0x110200,

  0x000000,0x000004,0x000000,0x000004,0x000080,0x000084,0x000080,0x000084,
  0x002000,0x002004,0x002000,0x002004,0x002080,0x002084,0x002080,0x002084,

  0x000000,0x000001,0x200000,0x200001,0x020000,0x020001,0x220000,0x220001,
  0x000002,0x000003,0x200002,0x200003,0x020002,0x020003,0x220002,0x220003,
};

static void
keycompperm(unsigned int left, unsigned int right, unsigned int *ek)
{
  unsigned int v0, v1;
  int i;

  for (i = 0; i < 16; i++) {
    left = (left << keysh[i]) | (left >> (28 - keysh[i]));
    left &= 0xfffffff0;
    right = (right << keysh[i]) | (right >> (28 - keysh[i]));
    right &= 0xfffffff0;
    v0 = comptab[6 * (1 << 4) + ((left >> (32 - 4)) & 0xf)]
      | comptab[5 * (1 << 4) + ((left >> (32 - 8)) & 0xf)]
      | comptab[4 * (1 << 4) + ((left >> (32 - 12)) & 0xf)]
      | comptab[3 * (1 << 4) + ((left >> (32 - 16)) & 0xf)]
      | comptab[2 * (1 << 4) + ((left >> (32 - 20)) & 0xf)]
      | comptab[1 * (1 << 4) + ((left >> (32 - 24)) & 0xf)]
      | comptab[0 * (1 << 4) + ((left >> (32 - 28)) & 0xf)];
    v1 = comptab[13 * (1 << 4) + ((right >> (32 - 4)) & 0xf)]
      | comptab[12 * (1 << 4) + ((right >> (32 - 8)) & 0xf)]
      | comptab[11 * (1 << 4) + ((right >> (32 - 12)) & 0xf)]
      | comptab[10 * (1 << 4) + ((right >> (32 - 16)) & 0xf)]
      | comptab[9 * (1 << 4) + ((right >> (32 - 20)) & 0xf)]
      | comptab[8 * (1 << 4) + ((right >> (32 - 24)) & 0xf)]
      | comptab[7 * (1 << 4) + ((right >> (32 - 28)) & 0xf)];
    ek[0] = (((v0 >> (24 - 6)) & 0x3f) << 26)
      | (((v0 >> (24 - 18)) & 0x3f) << 18)
      | (((v1 >> (24 - 6)) & 0x3f) << 10)
      | (((v1 >> (24 - 18)) & 0x3f) << 2);
    ek[1] = (((v0 >> (24 - 12)) & 0x3f) << 26)
      | (((v0 >> (24 - 24)) & 0x3f) << 18)
      | (((v1 >> (24 - 12)) & 0x3f) << 10)
      | (((v1 >> (24 - 24)) & 0x3f) << 2);
    ek += 2;
  }
}

void des_key_setup(byte key[8], unsigned int *ek)
{
  unsigned int left, right, v0, v1;

  v0 = key[0] | ((unsigned int)key[2] << 8) | ((unsigned int)key[4] << 16) | ((unsigned int)key[6] << 24);
  v1 = key[1] | ((unsigned int)key[3] << 8) | ((unsigned int)key[5] << 16) | ((unsigned int)key[7] << 24);
  left = ((v0 >> 1) & 0x40404040)
    | ((v0 >> 2) & 0x10101010)
    | ((v0 >> 3) & 0x04040404)
    | ((v0 >> 4) & 0x01010101)
    | ((v1 >> 0) & 0x80808080)
    | ((v1 >> 1) & 0x20202020)
    | ((v1 >> 2) & 0x08080808)
    | ((v1 >> 3) & 0x02020202);
  right = ((v0 >> 1) & 0x04040404)
    | ((v0 << 2) & 0x10101010)
    | ((v0 << 5) & 0x40404040)
    | ((v1 << 0) & 0x08080808)
    | ((v1 << 3) & 0x20202020)
    | ((v1 << 6) & 0x80808080);
  left = ((left << 6) & 0x33003300)
    | (left & 0xcc33cc33)
    | ((left >> 6) & 0x00cc00cc);
  v0 = ((left << 12) & 0x0f0f0000)
    | (left & 0xf0f00f0f)
    | ((left >> 12) & 0x0000f0f0);
  right = ((right << 6) & 0x33003300)
    | (right & 0xcc33cc33)
    | ((right >> 6) & 0x00cc00cc);
  v1 = ((right << 12) & 0x0f0f0000)
    | (right & 0xf0f00f0f)
    | ((right >> 12) & 0x0000f0f0);
  left = v0 & 0xfffffff0;
  right = (v1 & 0xffffff00) | ((v0 << 4) & 0xf0);

  keycompperm(left, right, ek);
}

void DES(unsigned int* key, byte* text, byte* C)
{
  int DEBUG = 0;
  unsigned int right, left, v0, v1;
  left = text[3] | ((unsigned int)text[2] << 8) | ((unsigned int)text[1] << 16) | ((unsigned int)text[0] << 24);
  right = text[7] | ((unsigned int)text[6] << 8) | ((unsigned int)text[5] << 16) | ((unsigned int)text[4] << 24);
  if(DEBUG) printf("%08X %08X \n", left, right);
  v0 = key[0];
  v0 ^= (right >> 1) | (right << 31);
  left ^= SB1[(v0 >> 26) & 0x3f]
    ^ SB3[(v0 >> 18) & 0x3f]
    ^ SB5[(v0 >> 10) & 0x3f]
    ^ SB7[(v0 >> 2) & 0x3f];
  v1 = key[1];
  v1 ^= (right << 3) | (right >> 29);
  left ^= SB2[(v1 >> 26) & 0x3f]
    ^ SB4[(v1 >> 18) & 0x3f]
    ^ SB6[(v1 >> 10) & 0x3f]
    ^ SB8[(v1 >> 2) & 0x3f];

  if (DEBUG) printf("%08X %08X \n", left, right);
  v0 = key[2];
  v0 ^= (left >> 1) | (left << 31);
  right ^= SB1[(v0 >> 26) & 0x3f]
    ^ SB3[(v0 >> 18) & 0x3f]
    ^ SB5[(v0 >> 10) & 0x3f]
    ^ SB7[(v0 >> 2) & 0x3f];
  v1 = key[3];
  v1 ^= (left << 3) | (left >> 29);
  right ^= SB2[(v1 >> 26) & 0x3f]
    ^ SB4[(v1 >> 18) & 0x3f]
    ^ SB6[(v1 >> 10) & 0x3f]
    ^ SB8[(v1 >> 2) & 0x3f];

  if (DEBUG) printf("%08X %08X \n", left, right);
  v0 = key[4];
  v0 ^= (right >> 1) | (right << 31);
  left ^= SB1[(v0 >> 26) & 0x3f]
    ^ SB3[(v0 >> 18) & 0x3f]
    ^ SB5[(v0 >> 10) & 0x3f]
    ^ SB7[(v0 >> 2) & 0x3f];
  v1 = key[5];
  v1 ^= (right << 3) | (right >> 29);
  left ^= SB2[(v1 >> 26) & 0x3f]
    ^ SB4[(v1 >> 18) & 0x3f]
    ^ SB6[(v1 >> 10) & 0x3f]
    ^ SB8[(v1 >> 2) & 0x3f];

  if (DEBUG) printf("%08X %08X \n", left, right);
  v0 = key[6];
  v0 ^= (left >> 1) | (left << 31);
  right ^= SB1[(v0 >> 26) & 0x3f]
    ^ SB3[(v0 >> 18) & 0x3f]
    ^ SB5[(v0 >> 10) & 0x3f]
    ^ SB7[(v0 >> 2) & 0x3f];
  v1 = key[7];
  v1 ^= (left << 3) | (left >> 29);
  right ^= SB2[(v1 >> 26) & 0x3f]
    ^ SB4[(v1 >> 18) & 0x3f]
    ^ SB6[(v1 >> 10) & 0x3f]
    ^ SB8[(v1 >> 2) & 0x3f];

  if (DEBUG) printf("%08X %08X \n", left, right);
  v0 = key[8];
  v0 ^= (right >> 1) | (right << 31);
  left ^= SB1[(v0 >> 26) & 0x3f]
    ^ SB3[(v0 >> 18) & 0x3f]
    ^ SB5[(v0 >> 10) & 0x3f]
    ^ SB7[(v0 >> 2) & 0x3f];
  v1 = key[9];
  v1 ^= (right << 3) | (right >> 29);
  left ^= SB2[(v1 >> 26) & 0x3f]
    ^ SB4[(v1 >> 18) & 0x3f]
    ^ SB6[(v1 >> 10) & 0x3f]
    ^ SB8[(v1 >> 2) & 0x3f];

  if (DEBUG) printf("%08X %08X \n", left, right);
  v0 = key[10];
  v0 ^= (left >> 1) | (left << 31);
  right ^= SB1[(v0 >> 26) & 0x3f]
    ^ SB3[(v0 >> 18) & 0x3f]
    ^ SB5[(v0 >> 10) & 0x3f]
    ^ SB7[(v0 >> 2) & 0x3f];
  v1 = key[11];
  v1 ^= (left << 3) | (left >> 29);
  right ^= SB2[(v1 >> 26) & 0x3f]
    ^ SB4[(v1 >> 18) & 0x3f]
    ^ SB6[(v1 >> 10) & 0x3f]
    ^ SB8[(v1 >> 2) & 0x3f];

  if (DEBUG) printf("%08X %08X \n", left, right);
  v0 = key[12];
  v0 ^= (right >> 1) | (right << 31);
  left ^= SB1[(v0 >> 26) & 0x3f]
    ^ SB3[(v0 >> 18) & 0x3f]
    ^ SB5[(v0 >> 10) & 0x3f]
    ^ SB7[(v0 >> 2) & 0x3f];
  v1 = key[13];
  v1 ^= (right << 3) | (right >> 29);
  left ^= SB2[(v1 >> 26) & 0x3f]
    ^ SB4[(v1 >> 18) & 0x3f]
    ^ SB6[(v1 >> 10) & 0x3f]
    ^ SB8[(v1 >> 2) & 0x3f];

  if (DEBUG) printf("%08X %08X \n", left, right);
  v0 = key[14];
  v0 ^= (left >> 1) | (left << 31);
  right ^= SB1[(v0 >> 26) & 0x3f]
    ^ SB3[(v0 >> 18) & 0x3f]
    ^ SB5[(v0 >> 10) & 0x3f]
    ^ SB7[(v0 >> 2) & 0x3f];
  v1 = key[15];
  v1 ^= (left << 3) | (left >> 29);
  right ^= SB2[(v1 >> 26) & 0x3f]
    ^ SB4[(v1 >> 18) & 0x3f]
    ^ SB6[(v1 >> 10) & 0x3f]
    ^ SB8[(v1 >> 2) & 0x3f];


  /*v0 = key[16];
  v0 ^= (right >> 1) | (right << 31);
  left ^= SB1[(v0 >> 26) & 0x3f]
    ^ SB3[(v0 >> 18) & 0x3f]
    ^ SB5[(v0 >> 10) & 0x3f]
    ^ SB7[(v0 >> 2) & 0x3f];
  v1 = key[17];
  v1 ^= (right << 3) | (right >> 29);
  left ^= SB2[(v1 >> 26) & 0x3f]
    ^ SB4[(v1 >> 18) & 0x3f]
    ^ SB6[(v1 >> 10) & 0x3f]
    ^ SB8[(v1 >> 2) & 0x3f];
  v0 = key[18];
  v0 ^= (left >> 1) | (left << 31);
  right ^= SB1[(v0 >> 26) & 0x3f]
    ^ SB3[(v0 >> 18) & 0x3f]
    ^ SB5[(v0 >> 10) & 0x3f]
    ^ SB7[(v0 >> 2) & 0x3f];
  v1 = key[19];
  v1 ^= (left << 3) | (left >> 29);
  right ^= SB2[(v1 >> 26) & 0x3f]
    ^ SB4[(v1 >> 18) & 0x3f]
    ^ SB6[(v1 >> 10) & 0x3f]
    ^ SB8[(v1 >> 2) & 0x3f];
  v0 = key[20];
  v0 ^= (right >> 1) | (right << 31);
  left ^= SB1[(v0 >> 26) & 0x3f]
    ^ SB3[(v0 >> 18) & 0x3f]
    ^ SB5[(v0 >> 10) & 0x3f]
    ^ SB7[(v0 >> 2) & 0x3f];
  v1 = key[21];
  v1 ^= (right << 3) | (right >> 29);
  left ^= SB2[(v1 >> 26) & 0x3f]
    ^ SB4[(v1 >> 18) & 0x3f]
    ^ SB6[(v1 >> 10) & 0x3f]
    ^ SB8[(v1 >> 2) & 0x3f];
  v0 = key[22];
  v0 ^= (left >> 1) | (left << 31);
  right ^= SB1[(v0 >> 26) & 0x3f]
    ^ SB3[(v0 >> 18) & 0x3f]
    ^ SB5[(v0 >> 10) & 0x3f]
    ^ SB7[(v0 >> 2) & 0x3f];
  v1 = key[23];
  v1 ^= (left << 3) | (left >> 29);
  right ^= SB2[(v1 >> 26) & 0x3f]
    ^ SB4[(v1 >> 18) & 0x3f]
    ^ SB6[(v1 >> 10) & 0x3f]
    ^ SB8[(v1 >> 2) & 0x3f];
  v0 = key[24];
  v0 ^= (right >> 1) | (right << 31);
  left ^= SB1[(v0 >> 26) & 0x3f]
  ^ SB3[(v0 >> 18) & 0x3f]
  ^ SB5[(v0 >> 10) & 0x3f]
  ^ SB7[(v0 >> 2) & 0x3f];
  v1 = key[25];
  v1 ^= (right << 3) | (right >> 29);
  left ^= SB2[(v1 >> 26) & 0x3f]
  ^ SB4[(v1 >> 18) & 0x3f]
  ^ SB6[(v1 >> 10) & 0x3f]
  ^ SB8[(v1 >> 2) & 0x3f];
  v0 = key[26];
  v0 ^= (left >> 1) | (left << 31);
  right ^= SB1[(v0 >> 26) & 0x3f]
  ^ SB3[(v0 >> 18) & 0x3f]
  ^ SB5[(v0 >> 10) & 0x3f]
  ^ SB7[(v0 >> 2) & 0x3f];
  v1 = key[27];
  v1 ^= (left << 3) | (left >> 29);
  right ^= SB2[(v1 >> 26) & 0x3f]
  ^ SB4[(v1 >> 18) & 0x3f]
  ^ SB6[(v1 >> 10) & 0x3f]
  ^ SB8[(v1 >> 2) & 0x3f];
  v0 = key[28];
  v0 ^= (right >> 1) | (right << 31);
  left ^= SB1[(v0 >> 26) & 0x3f]
  ^ SB3[(v0 >> 18) & 0x3f]
  ^ SB5[(v0 >> 10) & 0x3f]
  ^ SB7[(v0 >> 2) & 0x3f];
  v1 = key[29];
  v1 ^= (right << 3) | (right >> 29);
  left ^= SB2[(v1 >> 26) & 0x3f]
  ^ SB4[(v1 >> 18) & 0x3f]
  ^ SB6[(v1 >> 10) & 0x3f]
  ^ SB8[(v1 >> 2) & 0x3f];
  v0 = key[30];
  v0 ^= (left >> 1) | (left << 31);
  right ^= SB1[(v0 >> 26) & 0x3f]
  ^ SB3[(v0 >> 18) & 0x3f]
  ^ SB5[(v0 >> 10) & 0x3f]
  ^ SB7[(v0 >> 2) & 0x3f];
  v1 = key[31];
  v1 ^= (left << 3) | (left >> 29);
  right ^= SB2[(v1 >> 26) & 0x3f]
  ^ SB4[(v1 >> 18) & 0x3f]
  ^ SB6[(v1 >> 10) & 0x3f]
  ^ SB8[(v1 >> 2) & 0x3f];*/
  if(DEBUG) printf("%08X %08X \n", left, right);  
  v0 = left;
  v1 = right;
  C[7] = v0;
  C[6] = v0 >> 8;
  C[5] = v0 >> 16;
  C[4] = v0 >> 24;
  C[3] = v1;
  C[2] = v1 >> 8;
  C[1] = v1 >> 16;
  C[0] = v1 >> 24;
}

'CTF > Crypto' 카테고리의 다른 글

[Plaid CTF 2019] R u SAd?  (0) 2019.04.16
[0CTF/TCTF 2019] babyrsa  (0) 2019.03.28
[0CTF/TCTF 2019] zer0lfsr  (0) 2019.03.28
[0CTF/TCTF 2019] babysponge  (0) 2019.03.28
[2018 X-MAS CTF] Santa's list 2.0  (0) 2018.12.19
[2018 X-MAS CTF] Santa's list  (0) 2018.12.19
  Comments