조합형, 완성형 한글코드와 유니코드1. 소개2. 조합형 한글코드의 종류와 장, 단점3. 완성형 한글코드의 종류와 장, 단점4. 유니코드의 등장, 설명 및 장, 단점5. 인코딩 방식1. 소개초창기에 컴퓨터는 사실 "전자 계산기"로 불리며, 언어에 대한 수요가 없었다. 그러나, 당연히 언어를 표현하는 것에 대한 수요가 늘어나며, 문자를 컴퓨터로 시도하려는 연구가 시작 되었다. 그리고 우리가 익히 들어 알고 있는 ASCII 코드가 개발되며 영어권 국가에서는 문제 없이 문자를 컴퓨터로 표현할 수 있게 되었다. 하지만, 한국, 중국, 일본 등 다른 문화권 국가들의 언어는 1바이트인 ASCII 코드로 표현하는 것이 불가능했다. 우리나라의 입장에서, 한글을 컴퓨터로 표현하고자 하는 연구들이 진행 되었는데, 이 연구의 산물들이 조합형 한글코드, 완성형 한글코드 그리고 유니코드 이다.2. 조합형 한글코드의 종류와 장, 단점조합형 한글코드는 가장 초창기의 한글코딩 방식이다. 이는 글자의 초성, 중성, 종성에 각각 비트를 할당하여 합쳐서 컴퓨터의 화면에 뿌려주게 된다. 종류로는 N바이트조합형, 3바이트조합형, 2바이트조합형 한글코드가 있다. 조합형 한글코드의 가장 대표적인 장점은, 한글의 문자 체계 원리를 그대로 컴퓨터에 옮겨왔기 때문에 한글을 표현하는데 가장 좋은 코드형식이라는 점과 확장성이 좋다는 점이다. 이에 반해 단점은, 정렬 시에 (가~하) 한글 순서대로 정렬이 안되며, 다른 언어와의 호환성이 약하다는 점이다.( i ) N바이트조합형 한글코드8비트 컴퓨터가 출시되면서, 한글을 표시하기 위한 고육지책으로 만들어진 한글 표현 방식이다. 코딩 방식은, 한글의 자음과 모음을 영문자 하나하나에 대응시키고, Escape문자처럼 문자의 시작과 끝에 Shift In (^N) 과 Shit Out (^O) 를 추가해 한글과 영어를 구분하는 방식이다. 예를 들어, 단어 '네트워크' 는 '^N D g z W s f [ z ^O' 로 표시가 된다. 이 방식은 자음과 모음단위로 1바이트씩 사용하는데, 최소 2바이트에서 최대 5바이트까지의 데이터가 사용되어, 데이터 길이가 가변적이고, 처리하기 어려운 단점이 있었다. 이는 3바이트조합형 한글코드가 나오면서 사용하지 않게 되었다.[ N바이트조합형 한글코드 표 삽입]( ii ) 3바이트조합형 한글코드초성, 중성, 종성에 1바이트씩 할당해서 사용하는 방식이다. 중성과 종성이 없는 글자를 표현하기 위해서 채움 문자 (Fill Code) 가 정의되어 있다. N바이트조합형 한글코드는 데이터가 가변적이고 최대로 5바이트가 필요한 반면, 3바이트조합형 한글코드는 한글이 3바이트로 고정되어 표현될 수 있으므로 더 편리한 장점이 있었다. 하지만 이 역시 한 글자당 3바이트를 차지하게 되었으므로, 2바이트조합형이 출시되자 빠르게 사라졌다.( iii ) 2바이트조합형 한글코드초성, 중성, 종성에 5비트씩 할당하고, MSB는 1로 설정해 한글임을 표시하는 방식이다 (만약 MSB가 0이라면 영문과 숫자를 표시한다). 초기에는 여러 기업들이 자신들만의 조합형 방식을 만들어 각각 사용했다. 하지만 시간이 흐르면서, 삼보컴퓨터가 주도한 상용조합형(KSSM) 이 표준처럼 사용되었다. 현재까지 유일하게 남아있는 조합형 한글 표기방법이지만, 몇몇의 텍스트 편집 프로그램을 제외하고는 모두 완성형한글을 사용한다. 조합형은 폰트의 크기가 완성형에 비해 사이즈가 작고, 제작해야 하는 폰트의 개수가 적어 제작하기 용이한 장점이 있었으나, 윈도우95 운영체제가 출시될 때, 마이크로 소프트에서 확장완성형 한글 코딩 방식을 채택하게 됨으로써 조합형은 점점 사라져갔다.[ 2바이트조합형 한글코드 표 삽입]* 윈도우 95 출시 이전 한글문자와 한글글꼴을 컴퓨터에 띄우기 위해서는 BIOS를 직접 제어하거나, 별도의 한글카드라 불리는 하드웨어를 컴퓨터에 장착했어야 했다.3. 완성형 한글코드의 종류와 장, 단점완성형 한글코드의 기본적인 개념은 조합형처럼 초성, 중성, 종성을 조합시켜 문자를 만들어 내는 방식이 아니라, 이미 완성된 형태의 한글 낱자를 코드화 하여 사용하는 방식이라는 점이다. 즉, 각 글자마다 하나의 코드를 부여해서 사용하는 방식을 말한다. 완성형코드의 장점은 한글문자를 정렬할 수 있다는 점이며, 단점은 표현 불가능한 문자가 있다는 점이다. 하지만, 이 단점은 확장 완성형 코드와 유니코드가 나오면서 완화되었다. 마이크로 소프트에서 윈도우 95부터 완성형 한글코드를 한글코딩용 코드로 채택하면서, 조합형보다는 완성형 코드가 더 널리 사용된다. 종류로는 2바이트완성형과 확장완성형 코드가 있다. 사실 이전에 7비트완성형 코드도 있지만, 이 역시 2바이트완성형 코드가 나오면서 그 수요가 점차 줄어들었다.( i ) 2바이트완성형 한글코드2바이트를 이용해 완성된 음절을 코드와 일대일로 대응시키는 방식으로, KSC-5601표준안으로 채택된 방식이다. 기존의 ASCII코드와 겹치지 않기 위해 코드영역은 0xA1A1 부터 0xFEFE 까지로 제한되어, 총 8836개의 글자를 표시할 수 있다. 하지만, 실제로 한글에 사용하는 코드로는 2350자밖에 사용할 수 없었다. 자신의 핸드폰이 조금 오래된 핸드폰이라면 여기서 발생하는 문제점을 확인할 수 있는데, SMS창이나 텍스트 입력창에 '똠' 이나 '홥' 등 잘 사용하지 않는 문자를 입력하려 하면, 이를 제대로 표현하지 못하게 되는 현상이 일어남을 알 수 있다. 이 문제점은 1990년에 MBC드라마 '똠방각하'를 한글로 표기하지 못하면서 불거졌다고 하는데, 이 문제를 해결하기 위해 확장완성형이 고안되었다.( ii ) 확장완성형 한글코드앞서 말한 2바이트완성형의 문제를 해결하기 위해 마이크로소프트에서 새로운 코드 페이지를 고안해내는데, 그것이 바로 확장완성형 한글코드이다. 사실 코드페이지 자체는 IBM에서 처음으로 CP949 (Code Page 949)로 지정을 하였으나, 시간이 지나 마이크로소프트에서 이를 약간 변형하여 MS949를 만들었다. CP949 (=MS949)는 앞서 만들어진 2바이트완성형 한글코드와의 호환성을 유지하기 위해, 2바이트완성형에서 사용된 코드 영역은 그대로 두고, 남는 공간에 빠진 문자 8821자를 채워 넣어 윈도우95 운영체제에 한글 포맷으로 채택하게 된다. 호환성을 유지한다는 점에서 장점이 있지만, 남는 공간에 남은 문자들을 채워 넣은 방식이라, 조합형 한글코드와 마찬가지로 문자의 정렬 순서가 뒤죽박죽이라는 문제가 있었다.4. 유니코드의 등장, 설명 및 장, 단점한글에서는 이와 같이 조합형, 완성형과 같은 코드들이 만들어 졌지만, 중국, 일본, 러시아 등과 같은 나라에서도 자신들의 언어를 코드화 하려는 작업들이 일어났다. 그렇게 되면서, 같은 코드에 서로 다른 언어의 문자들이 할당되는 경우가 있었고, 이는 문자간의 호환을 불가능하게 만들었다. 이와 같은 불편함을 해소하고자 만들어진 것이 유니코드이다. 유니코드 1.0 은 1991년 8월에 만들어졌고, 그 후 5년이 지난 1996년에 유니코드 2.0이 나오면서 한글이 유니코드에 추가되었다. 유니코드의 가장 큰 장점은 다른 언어간의 호환이 가능하다는 점이고, 단점으로는 각 나라의 언어에 맞게 코딩이 되는 게 아니라 모든 언어를 포함하다 보니, 각 언어의 관점으로 봤을 때는 비효율성이 조금 있을 수 있다는 점이다. 예를 들어, 한글의 경우에는 조합형이 한글에 가장 좋은 형태이지만, 기술적인 요인과 환경적인 요인 때문에 확장완성형과 유니코드가 사용되고 있다.유니코드 5.2에서 한중일의 통합한자와 한글의 고어, 한글 자모의 원문자 등이 추가되어 사실상 한글의 역사를 볼 때 포함될 수 있는 모든 문자들이 포함되었다.5. 인코딩2바이트완성형 한글코드의 인코딩 방식은 EUC-KR, 확장완성형 한글코드의 인코딩 방식은 CP949 (MS949) 을 따른다. 따라서 EUC-KR은 2350자의 한글, CP949는 11172자의 한글을 표현할 수 있다. 일반적으로는 CP949 와 MS949를 동일한 개념으로 취급한다. 하지만 JAVA에서만큼은 EUC-KR과 CP949를 같은 것으로 취급하고, MS949를 다른 개념으로 취급한다. 따라서 설정 시, JAVA에서의 CP949는 EUC-KR와 같으므로 주의해야 한다.유니코드의 경우 인코딩 방식이 여러 개 존재한다. 그 중 가장 보편화된 인코딩 방식은 UTF-16과 UTF-8이다.( i ) UTF-16 인코딩UTF-16은 각 문자당 2바이트 혹은 4바이트를 사용하는 방식으로 가장 유니코드의 조합원리와 흡사한 포맷이지만, 영어권 국가들의 경우 모든 언어문자를 1바이트로 표현할 수 있기 때문에, 데이터를 낭비하는 측면이 있었다. 뿐만 아니라, ASCII코드와 호환이 되지 않는다는 점 때문에, UTF-16 대신 새로운 포맷인 UTF-8을 만들게 된다.( ii ) UTF-8 인코딩UTF-8은 기존의 ASCII 코드와 호환이 되게끔 만들어졌으며, 알파벳 표현부분에서 문자의 낭비가 없어 데이터량이 비교적 적었다. 그러면서 현재에는 대부분의 웹페이지에서 표준으로 잡아가고 있는 인코딩 방식이다.( iii ) EUC-KR, UTF-8, CP949의 관계윈도우는 마이크로소프트의 운영체제로 기본적으로 CP949 (MS949)를 인코딩 방식으로 지원하고 있다. 하지만 이는 운영체제 내부에서의 설정이고, 웹에서는 표준으로 UTF-8을 따르고 있다. 웹을 사용하지 않는다고 할 때, 이론적인 한글 표현 가능 관계는 다음과 같다.EUC-KR --> UTF-8 CP949하지만 웹에서의 관계는 위처럼 표현 가능한 것이 아니라, UTF-8이면 UTF-8, EUC-KR이면 EUC-KR끼리 밖에 제대로 표현을 하지 못한다. 따라서 한글로 웹 서비스를 제공하거나 웹 소스들을 사용할 때 인코딩 부분을 주의해서 사용해야 한다.인코딩을 확인해 보아야 할 주요 부분들은 다음과 같다.1. 서버 OS 인코딩 상태2. 웹 서버 인코딩 상태3. PHP 인코딩 상태4. 웹 소스 인코딩 상태5. 데이터베이스 사용 시, 데이터베이스 인코딩 상태-> 이 인코딩 방식들이 다 동일한 방식으로 되어있는지 확인해야 한다.
데이터 통신 프로젝트1. FHSS와 DSSS의 차이점FHSS는 Frequency Hopping Spread Spectrum의 줄임 말이다. 이는 처음 생성된 Source Signal을 여러 주파수로 건너뛰어 다니면서 변조를 해서 임의의 다른 사용자가 도청을 하거나 소스를 변경하지 못하도록 하는 기법이다. 즉, Modulation을 하는 주파수 대역을 여러 개로 설정하고 이 주파수 대역에 있어 순서를 정해서 건너뛰기를 하는 기법을 사용한다. 물론 송신자와 수신자는 이 순서를 알고 있기 때문에 신호를 복조 하는 것에 아무 문제가 없지만, 공격자의 입장에서는 주파수의 순서를 모르기 때문에 복조를 하기 어렵게 된다. 주파수의 건너뛰는 순서의 Cycle이 길어지면 길어질수록 공격자는 Brute Force 공격으로 순서를 예측하기가 더 힘들어지기 때문에 기밀성은 더 좋아질 수 있다. 또, 특정한 전자기파를 출력해서 통신을 방해하려는 경우에도, FHSS에서 사용하는 모든 주파수 대역에 대해서 출력하지 않는 한 영향을 받는 bit는 해당 주파수 대역을 사용하는 bit에 그치기 때문에 역시 좋은 속성을 가지고 있다.DSSS는 Direct Sequence Spread Spectrum의 약자이다. 이 역시 FHSS와 마찬가지로 원래의 소스 신호를 오직 지정된 송신자만 제대로 이해할 수 있도록 변조하는 기술이다. DSSS는 소스 신호를 변조하는 Chips Generator을 가지고 있는데, 여기서 만들어내는 특정 bit는 소스신호와 XNOR 연산을 해서 수신자에게 보낸다.『XNOR연산 진리표』ABOutput001010100111『DSSS 연산 진리표 - Ch06.pdf (Pg.44) 교안 참조』Source StreamChips GeneratorOutput Code001010100111이 Chips는 특정한 Pseudo-Random Sequence를 생성하고, 송신자와 수신자가 같은 메커니즘을 갖는 칩을 가지고 있기 때문에 변조와 복조를 문제 없이 할 수 있다. 임의의 공격자가 중간M 기술과 함께 사용되는 Spreading 방식이다.FHSS와 DSSS는 서로 호환되지 않고, 기밀성 측면에서는 좋은 특징을 보여주지만 무결성을 검증하기 위한 특정한 기법은 사용하지 않고, CRC-32 를 통해서 무결성을 검증한다.2. 소스코드 캡처본 (맨 마지막에 소스코드 텍스트 형식으로 실었습니다.)- 소스코드 설명Line 5~7보조 함수들의 선언.# SpreadingFunction : Spreading을 도와주는 함수.# DeSpreadingFunction : DeSpreading을 실행하는 함수.# checkInputValid : 입력값을 검증하는 함수. (0, 1이 아닌 값 들어왔을 시 에러 출력)Main 함수Line 10~16변수 선언 및 초기화# inputStream : 데이터를 입력 받는 변수# outputStream : 입력된 데이터를 Spreading한 이후의 값을 가지고 있는 변수# despreadStream : 다시 De-Spreading을 한 이후의 값을 가진 변수# DSSS : 교안에서 나온 Spreading을 위한 코드# wrongDSSS : 공격자에 의해 임의로 설정된 Spreading 실험용 코드Line 21~23메모리에 찌꺼기가 남아있지 않도록 제거Line 26~35입력을 받고 잘못된 입력 값을 받으면 다시 입력하도록 함.Line 38입력 값을 받았기 때문에 Spreading Process 실행.Line 41~45Spreading이 잘 실행 되었는지 Spreading 이후의 값 출력.Line 48~50이제 다시 De-Spreading과정을 통해서 원래의 입력 값을 복구.Line 53~56잘못된 Chips Code를 통해서 복구 했을 때의 예시를 보여주기 위한 코드.Spreading FunctionLine 61입력 값, 입력 값의 길이, Spreading을 위한 코드 값, 그리고 Spreading 이후 값을 위한 변수를 매개변수로 전달. 마지막 변수 char (*output)[12] 에서 굳이 숫자 12가 할당 된 이유는 교안에서는 변수입니다.DeSpreading FunctionLine 70Spreading당시 설정 된 outputStream값, inputLength값, DSSS코드값, Despreading 이후에 이 결과를 할당할 문자열을 매개변수로 전달합니다.Line 71한 입력 값이 11개의 Spreading Code와 결합되어 11bit를 생성해내기 dssslen = 11입니다. 그리고 OneCount와 ZeroCount를 넣은 이유는 중간에 bit가 잡음에 의해서 변경되거나 했을 때 이를 잡아주기 위해서 넣었습니다. 또한, 공격자가 임의의 코드를 통해서 복조를 하려 할 때 이 OneCount와 ZeroCount의 맞는 개수를 조절함으로써 보안성을 강화시킬 수 있습니다.Line 75~79OutputStream과 Spreading Code를 다시 XNOR 연산을 진행합니다. XNOR을 2번 연산하기 때문에 원래의 소스 값이 나올 수 밖에 없는데, 여기서 만약 중간에 간섭으로 인해 bit에서 변화가 있을 수 있기 때문에 if문에서 OneCount와 ZeroCount를 사용합니다.11bit중에서 몇 개가 1이고 몇 개가 0인지 세어주는 역할을 합니다.Line 82~85OneCount가 10개 이상이라면 무조건 원문이 1일 확률이 높기 때문에 1이라고 생각하고 DeSpread Stream의 bit를 1로 설정합니다. 반대로 ZeroCount가 10개 이상이라면 역시 원문이 0일 확률이 높기 때문에 0이라고 생각하고 bit를 0으로 설정합니다.만약 공격자가 임의로 코드를 만들어 해독하고자 할 때, OneCount가 10개가 이상이 안되거나 ZeroCount가 10개 이상이 안되면 E(Error)을 띄워줍니다. 여기서 10이라는 숫자는 제가 임의로 설정한 것이고 (전체 bit가 11bit이기 때문입니다) 만약 보안성을 조금 낮춘다면 Line 82, 83에서 10을 모두 더 낮은 값으로 바꾸면 됩니다. 하지만 이럴 경우 공격에 더 취약해질 수 있는 위험성이 있습니다.checkInputValude // Help Functionsvoid SpreadingFunction(char* input, int inputLength, char* dsss, char(*output)[12]);void DeSpreadingFunction(char(*output)[12], int inputLength, char* dsss, char* despreadStream);int checkInputValid(char* input, int inputLen);int main() {char inputStream[100]; //consider input as 100 byte.char outputStream[100][12]; //output stream after DSSSchar despreadStream[100]; //result after de-spreadingchar DSSS[12] = "10110111000";char wrongDSSS[5][12] = {"00001010111", "11010000111", "10001001010", "11111010101", "10101010101"};int inputStreamLength, idx;printf("Press Ctrl+c to exit.n");while (1) {// Initializememset(inputStream, '