A5/1 구현
대칭키 암호화의 스트림 사이퍼의 한 방법인
A5/1을 C++을 이용해서 구현해보았다.
키 값과 평문 입력
우선 키 값과 평문을 입력받는다.
키 값은 64자리의 2진수가 아니라면 오류 메시지를 표시하게 만들었다.
입력받은 평문은 글자 하나당 8비트로 저장해주었다.
1
2
3
// 문자를 8자리로 된 2진수로 바꾸는 과정
for (int i = 0; i < input.length(); i++)
plain_text += bitset<8>(input[i]).to_string();
bitset
함수를 이용하여 변환해주었다.
암호화 과정
1
2
3
4
5
6
7
// 암호화
void encrypt() {
make_keystream();
for (int i = 0; i < keystream.size(); i++)
cipher_text.push_back((plain_text[i] - '0') ^ keystream[i]);
}
암호화는 우선 키 스트림을 만들고
만들어진 키 스트림과 평문을 XOR연산하여 만들어준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 키 스트림 생성
void make_keystream() {
int len = plain_text.length();
for (int i = 0; i < len; i++) {
int maj = X[8] + Y[10] + Z[10];
if (maj > 1) {
if (X[8] == 1)
bit_shift('X');
if (Y[10] == 1)
bit_shift('Y');
if (Z[10] == 1)
bit_shift('Z');
}
else {
if (X[8] == 0)
bit_shift('X');
if (Y[10] == 0)
bit_shift('Y');
if (Z[10] == 0)
bit_shift('Z');
}
keystream.push_back(X[18] ^ Y[21] ^ Z[22]);
}
}
maj
값을 구한 후 해당하는 레지스터의 비트를 쉬프트해준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 키 스트림을 만드는 과정 중 비트 쉬프트와 [0]자리 값 생성
void bit_shift(char a) {
if (a == 'X') {
int t = X[13] ^ X[16] ^ X[17] ^ X[18];
for (int i = 18; i > 0; i--)
X[i] = X[i - 1];
X[0] = t;
}
else if (a == 'Y') {
int t = Y[20] ^ Y[21];
for (int i = 21; i > 0; i--)
Y[i] = Y[i - 1];
Y[0] = t;
}
else if (a == 'Z') {
int t = Z[7] ^ Z[20] ^ Z[21] ^ Z[22];
for (int i = 22; i > 0; i--)
Z[i] = Z[i - 1];
Z[0] = t;
}
}
복호화 과정
복호화를 하기 전 레지스터 값과 키 스트림 값을 초기화 해주었다.
1
2
3
4
5
6
7
// 복호화
void decrypt() {
make_keystream();
for (int i = 0; i < keystream.size(); i++)
res.push_back((cipher_text[i]) ^ keystream[i]);
}
복호화는 암호화와 마찬가지로 키 스트림을 만들어주고
만들어진 키 스트림과 암호문을 XOR연산해서 진행한다.
실행화면
전체 코드
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include<iostream>
#include<vector>
#include<bitset>
#include<math.h>
#include<string>
using namespace std;
vector<int>X(19);
vector<int>Y(22);
vector<int>Z(23);
vector<int>keystream;
vector<int>cipher_text;
vector<int>res;
string key, plain_text, input;
// 2진수로 된 문자열을 원래대로 복구하는 함수
string binary_to_string(vector<int>& arr) {
string res;
for (int i = 0; i < arr.size(); i += 8) {
int k = 0;
for (int j = 0; j < 8; j++)
k += arr[i + j] * pow(2, (7 - j));
res += (char)k;
}
return res;
}
// 키 스트림을 만드는 과정 중 비트 쉬프트와 [0]자리 값 생성
void bit_shift(char a) {
if (a == 'X') {
int t = X[13] ^ X[16] ^ X[17] ^ X[18];
for (int i = 18; i > 0; i--)
X[i] = X[i - 1];
X[0] = t;
}
else if (a == 'Y') {
int t = Y[20] ^ Y[21];
for (int i = 21; i > 0; i--)
Y[i] = Y[i - 1];
Y[0] = t;
}
else if (a == 'Z') {
int t = Z[7] ^ Z[20] ^ Z[21] ^ Z[22];
for (int i = 22; i > 0; i--)
Z[i] = Z[i - 1];
Z[0] = t;
}
}
// 키 스트림 생성
void make_keystream() {
int len = plain_text.length();
for (int i = 0; i < len; i++) {
int maj = X[8] + Y[10] + Z[10];
if (maj > 1) {
if (X[8] == 1)
bit_shift('X');
if (Y[10] == 1)
bit_shift('Y');
if (Z[10] == 1)
bit_shift('Z');
}
else {
if (X[8] == 0)
bit_shift('X');
if (Y[10] == 0)
bit_shift('Y');
if (Z[10] == 0)
bit_shift('Z');
}
keystream.push_back(X[18] ^ Y[21] ^ Z[22]);
}
}
// 암호화
void encrypt() {
make_keystream();
for (int i = 0; i < keystream.size(); i++)
cipher_text.push_back((plain_text[i] - '0') ^ keystream[i]);
}
// 복호화
void decrypt() {
make_keystream();
for (int i = 0; i < keystream.size(); i++)
res.push_back((cipher_text[i]) ^ keystream[i]);
}
int main() {
cout << "키 값을 입력해주세요(64비트) : ";
cin >> key;
if (key.length() != 64) {
cout << "키 값의 길이가 잘못되었습니다";
return 0;
}
for (int i = 0; i < 64; i++) {
if (key[i] != '0' && key[i] != '1') {
cout << "키 값이 잘못되었습니다";
return 0;
}
if (i < 19)
X[i] = key[i] - '0';
else if (i < 41)
Y[i - 19] = key[i] - '0';
else if (i < 64)
Z[i - 41] = key[i] - '0';
}
cout << "평문을 입력해주세요 : ";
getline(cin, input);
getline(cin, input);
// 문자를 8자리로 된 2진수로 바꾸는 과정
for (int i = 0; i < input.length(); i++)
plain_text += bitset<8>(input[i]).to_string();
cout << "평문의 이진수 표현 : " << plain_text << "\n\n";
cout << "A5/1을 이용해 암호화 중입니다.....\n\n";
encrypt();
cout << "만들어진 키 스트림 : ";
for (int i = 0; i < keystream.size(); i++)
cout << keystream[i];
cout << "\n암호화된 평문(이진수) : ";
for (int i = 0; i < cipher_text.size(); i++)
cout << cipher_text[i];
cout << "\n암호화된 평문(문자열) : " << binary_to_string(cipher_text) << "\n\n";
cout << "register 값과 keystream 값을 초기화하는 중입니다.....\n\n";
// 복호화하기 전 register 값과 keystream 값 초기화
for (int i = 0; i < 64; i++) {
if (i < 19)
X[i] = key[i] - '0';
else if (i < 41)
Y[i - 19] = key[i] - '0';
else if (i < 64)
Z[i - 41] = key[i] - '0';
}
keystream.clear();
cout << "복호화하는 중입니다.....\n\n";
decrypt();
cout << "복호화된 평문(문자열) : " << binary_to_string(res) << "\n";
return 0;
}