Seed 암호화 알고리즘 PHP 로 구현

Seed for PHP

첨부 파일
class.seed.php30.3KB

한국인터넷진흥원에서 제공하는 Seed 암호화 알고리즘을 PHP로 구현하였습니다.

한국인터넷진흥원에서 제공하고 있는 Seed 암호화 알고리즘을 PHP로 구현
Seed란 무엇인가?

발췌 : http://seed.kisa.or.kr/kor/seed/seedInfo.jsp
*SEED 암호알고리즘
   SEED는 전자상거래, 금융, 무선통신 등에서 전송되는 개인정보와 같은 중요한 정보를 보호하기 위해 1999년 2월 한국인터넷진흥원과 국내 암호전문가들이 순수 국내기술로 개발한 128비트 블록 암호 알고리즘입니다.
   1999년에는 128비트 키를 지원하는 SEED 128을 개발하였으며, 암호 알고리즘 활용성 강화를 위해 2009년 256 비트 키를 지원하는 SEED 256을 개발하였습니다.
*표준화 현황
   SEED 128은 1999년 9월 정보통신단체표준(TTA)으로 제정되었으며, 2005년에는 국제 표준화 기구인 ISO/IEC 국제 블록암호알고리즘, IETF 표준으로 제정되었습니다.
현재 한국인터넷 진흥원에서는 SEED암호화 알고리즘을 공인인증서 개인키를 저장할때 SEED로 암호화 하여 저장하도록 권고하고 있습니다.

출처 : http://www.rootca.or.kr/kor/standard/standard01B.jsp
# 암호 알고리즘 규격[v1.21] (PDF파일 3쪽 발췌)
[ 공인인증시스템 및 가입자 설비는 가입자의 전자서명키가 패스워드 기반으로 암호화되어 저장될 수 있도록 SEED . 블록 암호알고리즘을 구현할 것을 권고한다 ]

왜 필자는 그 많은 삽질을 해가면 SEED를 PHP로 구현하였는가?
발단은 공인인증서를 이용한 서명을 PHP로 해보고 싶었던것입니다.
공인인증서 서명을 위해 SEED를 PHP로 구현해야만 했습니다.
그리하여 무한삽질을 시작하였습니다.

SEED샘플은 오직 C와 Java버젼만 있어서 PHP 구현을 위해서는 구현된 샘플 소스가 필요했습니다.
seed.kisa.or.kr 홈페이지를 방문하여 SEED보급신청을 통해 이메일로 SEED 가 구현된 Java 버젼을 다운 받을수 있었습니다.
(http://seed.kisa.or.kr/kor/seed/request01.jsp)

다운을 받아 이클립스에서 샘플파일을 충분히 테스트하고 SEED_KISA.java 파일을 PHP로 컨버팅 하기 시작했습니다.

그냥 java를 php로 만 바꾸면 쉽게 풀릴거 같았습니다.
대충 오류는 나지않게 컨버팅 과정에 기존 프로그램 알고리즘이 최대한 변경되지 않은 상태로 PHP를 컨버팅을 했습니다.
몇시간 고생해서 오류는 나지않게 변경하고 몇가지 손을 보고 최적화 작업을 마칠수 있었습니다.

이제 테스트만 하면 바로 끝날꺼 같았습니다. 테스트는 다음과 같이 이루어졌습니다.


여러번의 삽질 결과로 다음과 같은 결과를 얻었습니다.

[ Test Encrypt mode ]
Key : 00 00 00 69 00 00 00 00 00 00 00 00 00 00 00 48 
Plaintext : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 
Ciphertext : 82 e4 56 e0 3a 24 6f ca 35 52 ae b7 8a c8 63 c1 

[ Test Decrypt mode ]
Key : 00 00 00 69 00 00 00 00 00 00 00 00 00 00 00 48 
Ciphertext : 82 e4 56 e0 3a 24 6f ca 35 52 ae b7 8a c8 63 c1 
Plaintext : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 

대만족이었습니다. 생각보다 쉽게 풀리는듯 했습니다.

다음 강좌에 올리겠지만 
최종 공인인증서 서명을 위해 컨버팅한 seed 를 사용하여 개인키를 추출했습니다.
헛~ 하지만 결과 값이 달랐습니다.
컨버팅이 쉽제 되지 않을거라 예상했던터라 한단계씩 원인을 찾아 나섰습니다.

원인을 찾아보니 첫번째 실행한 SeedRoundKey 함수에서 리턴된 
PHP $pdwRoundKey 값과 Java 의 pdwRoundKey값이 다르다는걸 알게 되었습니다.

그래서 자세히 소스를 살펴보고 살펴 보았습니다.
그럴수록 이상하게 잘못된 점을 찾지 못하고 있었습니다. 

결국 하나하나 값을 찍어보고 확인하고 있던중 깜짝놀라지 않을수가 없었습니다.

PHP소스

결과
—————————————-
A : a0cf4d5b 
C : 13f93b51 
KC : 3c6ef373 
T00 : 80000000 
—————————————-

Java소스

결과
—————————————-
A0 : a0cf4d5b
C0 : 13f93b51
KC0 : 3c6ef373
T0 : 78599539
—————————————-

여러분들은 두개의 다른점을 이해 하셨나요? 저는 절대로 몰랐을 것입니다.
C++ 달인 Keige 께서 도움을 주지 못하셨다면 저는 절대로 몰랐을 것입니다.

결론은 PHP에서는 float -> int 형으로 강제 형변환 할때 손실처리가 제대로 되지 않다는 것이었습니다.
그것도 int의 -한계값인 -2147483648 보다 작을때만 처리되지 않았습니다.
그래서 좀더 디테일하게 테스트했습니다.

결과값
—————————
float(-44275830471) 
int(-2147483648) 
나와야할값 : -1326157511

float(44275830471) 
int(1326157511) 

보시는것처럼 float 음수 값을 int형으로 형변환 할경우
int의 -최대값으로 변한것을 알수 있습니다.
원래는 -1326157511 값이 나와야 하는데 말이죠

참 난감했습니다. PHP로는 만들수 없는건가? 하면서 포기해야 하나 생각까지도 했습니다.
그래서 강제로 float 값을 int로 형변환 하는 함수를 만들어 보기로 했으며
여러번 삽질끝에 다음과 같은 함수를 만들었습니다.

제가 고수가 아니기때문에 고수님의들 이함수의 완벽성 점검이 필요합니다.

이함수는 int 형으로 변환하는 구분에는 결과값에
$T0 = $this->ConvertInt($T0);
라고 한번더 작업을 해야만 했습니다.

완료한후 다시 최종테스트를 통해 문제가 없음을 확인하고 이렇게 여러분에게 오픈합니다.
심각한 버그가 있다면 알려주시고 같이 보안해 나갔으면 합니다.^^

다음 강좌는 PHP용 Seed 클래스를 이용하여 우리가 널리 사용하고 있는 yesign 공인인증서 전자서명이란걸 해볼려고 합니다.
감사합니다.


]]>

도큐멘트 에 올린 글

댓글 남기기