[암호학] 3. DES를 C언어로 구현해보았다.
[암호학] 3. DES를 C언어로 구현해보았다.
DES Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <stdio.h>
#include <string.h>
#include <stdint.h>
unsigned int IP[] = { ...
unsigned int inv_IP[] = { ...
unsigned int S[8][4][16] = { ...
unsigned int E[] = { ...
unsigned int P[] = { ...
unsigned int PC1[] = { ...
unsigned int PC2[] = { ...
uint8_t get_bit(unsigned char *data, int n) { //비트로 변환
// n은 1 ~ 64
int byte_index = (n - 1) / 8; // 몇 번째 바이트에 있는지 계산 (0 ~ 7)
int bit_index = (n - 1) % 8; // 그 바이트 내에서 몇 번째 비트인지 계산 (0 ~ 7)
// 바이트 내에서는 왼쪽(MSB)부터 0번 인덱스 취급하므로 7에서 빼줍니다.
return (data[byte_index] >> (7 - bit_index)) & 1;
}
void f_function(unsigned int *R, unsigned int *Key) {
unsigned int ER[49];
for (int i = 1; i < 49; i++){ //Expansion & Key XOR
ER[i] = R[E[i-1]];
ER[i] ^= Key[i];
}
unsigned int row;
unsigned int column;
for (int i = 0; i < 8; i++) //ER을 S박스에 넣어서 나온 값을 R에 넣기
{
row = (ER[i * 6 + 1] << 1) | ER[i * 6 + 6];
column = (ER[i * 6 + 2] << 3) | (ER[i * 6 + 3] << 2) | (ER[i * 6 + 4] << 1) | ER[i * 6 + 5];
R[i*4 + 1] = (S[i][row][column] >> 3) & 1; // 8의 자리
R[i*4 + 2] = (S[i][row][column] >> 2) & 1; // 4의 자리
R[i*4 + 3] = (S[i][row][column] >> 1) & 1; // 2의 자리
R[i*4 + 4] = (S[i][row][column] >> 0) & 1; // 1의 자리
}
unsigned int Final_R[33];
for (int i = 0; i < 32; i ++)
Final_R[i+1] = R[P[i]];
memcpy(R + 1, Final_R + 1, sizeof(unsigned int) * 32); //코드 복사
};
void Key_Transform(unsigned int *C, unsigned int *D) {
//Left Shift
unsigned int num = C[1];
memcpy(C + 1, C + 2, sizeof(unsigned int) * 27);
C[28] = num;
num = D[1];
memcpy(D + 1, D + 2, sizeof(unsigned int) * 27);
D[28] = num;
};
unsigned char plaintext[] = "QWERASDF";
unsigned char key_str[] = "KCHTBLOG";
int main() {
unsigned int bitpt[65]; //평문 비트화
unsigned int R[33]; //평문 R
unsigned int L[33]; //평문 L
for (int i = 1; i <= 64; i++)
bitpt[i] = get_bit(plaintext, IP[i-1]); //평문 비트화 하기, IP까지 한번에
memcpy(L + 1, bitpt + 1, sizeof(unsigned int) * 32);
memcpy(R + 1, bitpt + 33, sizeof(unsigned int) * 32);
unsigned int Key[65];
unsigned int C[29]; //Key C
unsigned int D[29]; //Key D
for (int i = 1; i <= 64; i++)
Key[i] = get_bit(key_str, i); //키 비트화 하기
for (int i = 1; i <= 28; i++){
C[i] = Key[PC1[i - 1]];
D[i] = Key[PC1[i + 27]];
}
//round 1
unsigned int Round_Key[49];
unsigned int Out_R[33];
unsigned int Out_L[33];
for (int k = 1; k <= 16; k++){
Key_Transform(C,D); //transform
if (k != 1 && k != 2 && k != 9 && k != 16) //이 때는 2번이므로
Key_Transform(C,D); //transform
memcpy(Key + 1, C + 1, sizeof(unsigned int) * 28);
memcpy(Key + 29, D + 1, sizeof(unsigned int) * 28);
for (int i = 1; i <= 48; i++) //라운드 키 생성
Round_Key[i] = Key[PC2[i-1]]; //PC22
memcpy(Out_L + 1, R + 1, sizeof(unsigned int) * 32); //Out_L 만들기
f_function(R, Round_Key); //R에 f-function 적용
for (int i = 1; i <= 32; i++) //Out_R 만들기
Out_R[i] = L[i] ^ R[i];
memcpy(R + 1, Out_R + 1, sizeof(unsigned int) * 32); //R에 Out_R 대입 (f_function 반복사용하기 위함)
memcpy(L + 1, Out_L + 1, sizeof(unsigned int) * 32); //L에 Out_L 대입 (f_function 반복사용하기 위함)
}
memcpy(bitpt + 1, R + 1, sizeof(unsigned int) * 32); //마지막에 한번 더 전치를 하기 때문에 R이 먼저
memcpy(bitpt + 33, L + 1, sizeof(unsigned int) * 32);
unsigned int bitct[65]; //암호문
for (int i = 1; i <= 64; i++) //inv_IP
bitct[i] = bitpt[inv_IP[i-1]];
printf("Ciphertext (HEX): ");
for (int i = 0; i < 8; i++) {
unsigned int byte = 0;
for (int j = 1; j <= 8; j++)
byte = (byte << 1) | bitct[i * 8 + j];
printf("%02X ", byte);
}
printf("\n");
return 0;
}
지난번 포스팅에는 f함수까지 구현했는데 이번에는 라운드 적용부터 inv_IP까지 적용했다. 가장 실수를 많이 했던 부분은 다음과 같다.
1
2
3
4
5
6
7
8
//이 행렬들은 모두 원소가 1부터 시작한다.
unsigned int IP[] = { ...
unsigned int inv_IP[] = { ...
unsigned int S[8][4][16] = { ...
unsigned int E[] = { ...
unsigned int P[] = { ...
unsigned int PC1[] = { ...
unsigned int PC2[] = { ...
C언어는 배열의 원소는 0부터 시작하는데, 구해온 DES의 행렬들은 원소가 1부터 시작한다. 따라서 코드의 index를 실수하지 않도록 신경써야 한다.
DES에서 QWERASDF를 EDB로 KCHTBLOG라는 키를 이용하여 암호화 한 내용이 이와 같다.
github에서 내 코드를 실행한 것과 같은 값으로 암호화가 되었다.
This post is licensed under CC BY 4.0 by the author.
