상세 컨텐츠

본문 제목

SEED 암호화/복호화 PHP 버전 , KISA SEED-CBC 이용, Encryption, Decryption

카테고리 없음

by 동해둘리 2019. 3. 31. 21:02

본문

반응형

서버간의 데이터 전달시, 평문으로 전달되는 것을 막기위해 암호화를 하는 경우가 있는데요, PHP 의 base64_encode 와 base64_decode 를 이용하기도 하지만, base64의 경우는 암호화/복호화 할때 키값을 사용하지 않기 때문에 전달되는 값을 알기만 하면 누구나 복호화를 할 수 있는 단점이 있습니다

 

그래서, 암호화 할때 키값을 이용하여 암호화 하고, 복호화 하는 측에서도 키값을 알아야만 복호화 할 수 있는 방식이 보다 안정적인 암호화 방식이라고 할 수 있습니다

 

이번에 소개할 암호화 솔루션은 한국인터넷 진흥원 (KISA)에서 개발하여 배포하는 암호화 솔루션인 SEED 에 대해 살펴보고자 합니다. 아래 사이트에서 관련 정보를 얻을 수 있으며, 예제 소스도 다운로드 할 수 있습니다

 

 

 

 

 

사이트 접속 후 자료실의 [암호알고리즘 소스코드] 메뉴를 클릭하시면 여러가지 암호화 솔루션의 소스코드를 다운로드 받을 수 있습니다.

 

SEED-CBC 암호화/복호화 예제

 

 

저는, 블록암호 SEED 사용하기로 하여 해당 파일을 다운로드 받았습니다. 압축을 풀면 C/C++ 을 비롯하여 JAVA, JSP, ASP, PHP 등의 소스가 보입니다. 저의 경우는 PHP 를 사용하기 때문에 PHP 코드를 사용하였습니다.

 

 

PHP 소스를 다운받아서 서버에 업로드 한 후 확인해보면, 위와 같이 나오는데, 이상하게도 평문에 홍길동 이라고 입력하고 암호화 한다음에, 해당 암호문을 오른쪽 암호문 창에 넣고 복호화를 해보면 홍길동이 나오지 않더라구요

 

살펴보니, 아래부분에 나와있는 설명대로 KISA 에서 제공하는 예제파일이 입력받는 평문이라함은 일반적인 문자열이 아니라 Hex 값으로 변환된 문자열 이었습니다.

 

 

 

그래서, 정리를 해보니...... 다음과 같습니다

 

상황 ) A 서버에서 B 서버로 홍길동 이라는 값을 암호화하여 넘기는 경우 

 

1. A 서버 : 홍길동을 Hex 값으로 변경한다 

2. A 서버 : 변경된 Hex 값으로 암호화 Encryption 한다. 

3. A 서버 : 암호화된 Hex 값을 다시 문자열로 변경한다.

4. A 서버 : 문자열로 변경된 암호화된 Hex 값을 Base64로 인코딩 한다.

 

5. B 서버 : 전달받은 암호문을 Base64로 디코딩 한다.

6. B 서버 : Base64로 디코딩 된 값을 Hex 값으로 변경한다.

7. B 서버 : Hex 값으로 변경된 값을 Decryption 한다.

8. B 서버 : 디코드된 값을 스트링으로 변경한다. 

 

 

 

이를 실행하기 위한 코드를 설명합니다.

 

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
require_once ('KISA_SEED_CBC.php'); // 다운로드 받은 KISA 의 소스 include 
 
 
 
// 사용자 키값을 세팅하는 부분
$g_bszUser_key = null;  
if(isset($_POST['KEY']))
    $g_bszUser_key = $_POST['KEY'];
if($g_bszUser_key == null)
{
    // 아래의 키값을 임의로 설정하고 B 서버측에서 디코딩 할때도 같은 키값을 사용해야 합니다.
    $g_bszUser_key = "0x19,0x31,0x32,0x8F,0x18,0x17,0x79,0xF1,0xE9,0xF3,0x94,0x37,0x0A,0xD4,0x05,0x89";
}
 
// 초기화 키값을 세팅하는 부분     
$g_bszIV = null;
if(isset($_POST['IV']))
    $g_bszIV = $_POST['IV'];
if($g_bszIV == null)
{
    // 아래의 키값을 임의로 설정하고 B 서버측에서 디코딩 할때도 같은 키값을 사용해야 합니다.
    $g_bszIV = "0x24,0x83,0x16,0xA7,0x35,0xA2,0x11,0x81,0x6F,0xB3,0xD9,0x1A,0x36,0x16,0x25,0x01";
}
 
 
cs

 

 

 

 

 

아래 부분은 암호화/복호화를 담당하는 Encryption 함수와 Decryption 함수입니다

 

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
function decrypt($bszIV, $bszUser_key, $str) {
 
    $planBytes = explode(",",$str);
    $keyBytes = explode(",",$bszUser_key);
    $IVBytes = explode(",",$bszIV);
    
    for($i = 0; $i < 16; $i++)    {
        $keyBytes[$i] = hexdec($keyBytes[$i]);
        $IVBytes[$i] = hexdec($IVBytes[$i]);
    }
 
    for ($i = 0; $i < count($planBytes); $i++) {
        $planBytes[$i] = hexdec($planBytes[$i]);
    }
 
    if (count($planBytes) == 0) {
        return $str;
    }
 
    $pdwRoundKey = array_pad(array(),32,0);
    $bszPlainText = null;
 
    // 방법 1
    $bszPlainText = KISA_SEED_CBC::SEED_CBC_Decrypt($keyBytes, $IVBytes, $planBytes, 0, count($planBytes));
    for($i=0;$i< sizeof($bszPlainText);$i++) {
        $planBytresMessage .= sprintf("%02X", $bszPlainText[$i]).",";
    }
    return substr($planBytresMessage,0,strlen($planBytresMessage)-1);
}
 
 
 
function encrypt($bszIV, $bszUser_key, $str) {
    $planBytes = explode(",",$str);
    $keyBytes = explode(",",$bszUser_key);
    $IVBytes = explode(",",$bszIV);
    
    for($i = 0; $i < 16; $i++)    {
        $keyBytes[$i] = hexdec($keyBytes[$i]);
        $IVBytes[$i] = hexdec($IVBytes[$i]);
    }
    for ($i = 0; $i < count($planBytes); $i++) {
        $planBytes[$i] = hexdec($planBytes[$i]);
    }
 
    if (count($planBytes) == 0) {
        return $str;
    }
   $ret = null;
 
    $bszChiperText = null;
 
   $pdwRoundKey = array_pad(array(),32,0);
 
 
 
   //방법 1
 
    $bszChiperText = KISA_SEED_CBC::SEED_CBC_Encrypt($keyBytes, $IVBytes, $planBytes, 0, count($planBytes));
    $r = count($bszChiperText);
 
 
    for($i=0;$i< $r;$i++) {
        $ret .= sprintf("%02X", $bszChiperText[$i]).",";
    }
 
    return substr($ret,0,strlen($ret)-1);
 
}
 
 
cs

 

 

 

 

 

 

아래 두 함수는 문자열을 Hex 값으로 변경하거나 Hex 값을 문자열로 변경해주는 함수입니다

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function strToHex($string){
$hex='';
for ($i=0; $i < strlen($string); $i++){
$hex .= "," . dechex(ord($string[$i]));
        
}
return $hex;
}
 
 
function hexToStr($hex){
$string='';
for ($i=0; $i < strlen($hex)-1; $i+=2){
$string .= chr(hexdec($hex[$i].$hex[$i+1]));
}
return $string;
 
}
cs

 

 

 

 

 

 

지금부터는 앞서 설명한 A서버에서 B서버로 전달하는 과정과 일치하는 순서입니다

 

 

 

 

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
// 최초의 입력문자열 
$str = "홍길동";
echo "1. 최초 입력값: ";
echo $str;
echo "<Br><br>";
 
// 1. A 서버 : 홍길동을 Hex 값으로 변경한다 
$str = strToHex($str);
$str = substr( $str , 1, strlen($str)); // Hex 값으로 변환시 각 값 사이에 콤마를 찍게되는데, 맨 앞의 콤마를 삭제합니다. 
echo "2. 홍길동 헥사값 : ";
echo $str;
echo "<Br><br>";
 
// 2. A 서버 : 변경된 Hex 값으로 암호화 Encryption 한다. 
$return = encrypt($g_bszIV, $g_bszUser_key, $str);
echo "3. 헥사값을 암호화:";
echo $return;
echo "<Br><br>";
 
// 3. A 서버 : 암호화된 Hex 값을 다시 문자열로 변경한다.
$return = str_replace(",","", $return);  // 암호화 후, 결과값은 Hex 로 나오는데, 그 값들 사이의  콤마를 없애줍니다. 
$return = hexToStr( $return); 
echo "4. 암호화를 다시 스트링 : ";
echo $return;
echo "<Br><br>";
 
 
// 4. A 서버 : 문자열로 변경된 암호화된 Hex 값을 Base64로 인코딩 한다.
echo "5. 암호화를 base64_encode : ";
$return = base64_encode($return);
echo $return;
echo "<Br><br>";
 
 
// 5. B 서버 : 전달받은 암호문을 Base64로 디코딩 한다.
echo "6. 암호화를 base64_decode : ";
$return = base64_decode($return);
echo $return;
echo "<Br><br>";
 
 
// 6. B 서버 : Base64로 디코딩 된 값을 Hex 값으로 변경한다.
$return = strToHex($return);
$return = substr( $return , 1, strlen($return));  // Hex 변환시 값 사이에 콤마를 찍는데, 맨 앞의 콤마를  삭제합니다.
echo "7. 디코드를 헥사 : ";
echo $return;
echo "<Br><br>";
 
 
// 7. B 서버 : Hex 값으로 변경된 값을 Decryption 한다.
 
$return = decrypt($g_bszIV, $g_bszUser_key, $return);
echo "8. 암호화를 복호화:";
echo $return;
echo "<Br><br>";
 
// 8. B 서버 : 디코드된 값을 스트링으로 변경한다. 
$return = str_replace(",","", $return); // 디코드된 Hex 값 사이의 콤마를 제거합니다. 
$return = hexToStr( $return);
echo "9. 복호화를 스트링 : ";
echo $return;
echo "<Br><br>";
 
 
 
 
cs

 

 

 

 

 

 

 

 

여기까지 진행하게 되면 화면에 이렇게 표시가 됩니다

 

 

아래에 전체 소스코드를 남깁니다

 

 

 

 

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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
<html>  
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>국산암호 [SEED - CBC] 테스트 페이지</title>
</head>
<body>
<?
 
require_once ('KISA_SEED_CBC.php');
 
$g_bszUser_key = null;
if(isset($_POST['KEY']))
    $g_bszUser_key = $_POST['KEY'];
if($g_bszUser_key == null)
{
    $g_bszUser_key = "0x19,0x31,0x32,0x8F,0x18,0x17,0x79,0xF1,0xE9,0xF3,0x94,0x37,0x0A,0xD4,0x05,0x89";
}
    
$g_bszIV = null;
if(isset($_POST['IV']))
    $g_bszIV = $_POST['IV'];
if($g_bszIV == null)
{
    $g_bszIV = "0x24,0x83,0x16,0xA7,0x35,0xA2,0x11,0x81,0x6F,0xB3,0xD9,0x1A,0x36,0x16,0x25,0x01";
}
 
function decrypt($bszIV$bszUser_key$str) {
 
    $planBytes = explode(",",$str);
    $keyBytes = explode(",",$bszUser_key);
    $IVBytes = explode(",",$bszIV);
    
    for($i = 0$i < 16$i++)
    {
        $keyBytes[$i= hexdec($keyBytes[$i]);
        $IVBytes[$i= hexdec($IVBytes[$i]);
    }
 
    for ($i = 0$i < count($planBytes); $i++) {
        $planBytes[$i= hexdec($planBytes[$i]);
    }
 
    if (count($planBytes== 0) {
        return $str;
    }
 
    $pdwRoundKey = array_pad(array(),32,0);
 
    $bszPlainText = null;
 
    // 방법 1
    $bszPlainText = KISA_SEED_CBC::SEED_CBC_Decrypt($keyBytes$IVBytes$planBytes0count($planBytes));
 
    for($i=0;$i< sizeof($bszPlainText);$i++) {
        $planBytresMessage .= sprintf("%02X"$bszPlainText[$i]).",";
    }
 
    return substr($planBytresMessage,0,strlen($planBytresMessage)-1);
}
 
function encrypt($bszIV$bszUser_key$str) {
    $planBytes = explode(",",$str);
    $keyBytes = explode(",",$bszUser_key);
    $IVBytes = explode(",",$bszIV);
    
    for($i = 0$i < 16$i++)
    {
        $keyBytes[$i= hexdec($keyBytes[$i]);
        $IVBytes[$i= hexdec($IVBytes[$i]);
    }
    for ($i = 0$i < count($planBytes); $i++) {
        $planBytes[$i= hexdec($planBytes[$i]);
    }
 
    if (count($planBytes== 0) {
        return $str;
    }
    $ret = null;
    $bszChiperText = null;
    $pdwRoundKey = array_pad(array(),32,0);
 
    //방법 1
    $bszChiperText = KISA_SEED_CBC::SEED_CBC_Encrypt($keyBytes$IVBytes$planBytes0count($planBytes));
 
    $r = count($bszChiperText);
 
    for($i=0;$i$r;$i++) {
        $ret .= sprintf("%02X"$bszChiperText[$i]).",";
    }
    return substr($ret,0,strlen($ret)-1);
}
 
function strToHex($string){
$hex='';
for ($i=0$i < strlen($string); $i++){
$hex .= "," . dechex(ord($string[$i]));
        
}
return $hex;
}
 
function hexToStr($hex){
$string='';
for ($i=0$i < strlen($hex)-1$i+=2){
$string .= chr(hexdec($hex[$i].$hex[$i+1]));
}
return $string;
}
 
$str = "홍길동";
echo "1. 최초 입력값: ";
echo $str;
echo "<Br><br>";
 
$str = strToHex($str);
$str = substr$str , 1, strlen($str));
echo "2. 홍길동 헥사값 : ";
echo $str;
echo "<Br><br>";
 
$return = encrypt($g_bszIV$g_bszUser_key$str);
echo "3. 헥사값을 암호화:";
echo $return;
echo "<Br><br>";
 
 
$return = str_replace(",",""$return);
$return = hexToStr( $return);
echo "4. 암호화를 다시 스트링 : ";
echo $return;
echo "<Br><br>";
 
 
echo "5. 암호화를 base64_encode : ";
$return = base64_encode($return);
echo $return;
echo "<Br><br>";
 
 
echo "6. 암호화를 base64_decode : ";
$return = base64_decode($return);
echo $return;
echo "<Br><br>";
 
 
$return = strToHex($return);
$return = substr$return , 1, strlen($return));
echo "7. 디코드를 헥사 : ";
echo $return;
echo "<Br><br>";
 
 
 
$return = decrypt($g_bszIV$g_bszUser_key$return);
echo "8. 암호화를 복호화:";
echo $return;
echo "<Br><br>";
 
$return = str_replace(",",""$return);
$return = hexToStr( $return);
echo "9. 복호화를 스트링 : ";
echo $return;
echo "<Br><br>";
 
?>
 
</body>
</html>
cs

 

 


암호화된 Hex 값을 스트링으로 변환하는 것을 안하는 바람에 이틀밤을 꼬박 노가다 작업을 하다가 알게되었네요. 알고나니 별겨 아닌데하는 기분, 늘 느끼게 됩니다. 모쪼록, 저와 같은 고생을 하는 분이 없기를 바랍니다^^

반응형

댓글 영역