2019. 3. 28. 17:58, CTF/Crypto
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