Erzsamatory Weblog


웹 프로그래밍을 하다보면 데이터를 암호화 해야 하는 경우가 많이 발생합니다. 개인정보와 같은 민감한 정보는 당연히 암호화를 한 후에 데이터베이스에 저장을 해야 하고, 기타 프로그램 보안상 중요한 데이터 역시 암호화를 한 후에 저장을 하는 것이 일반적입니다. PHP에는 암호화를 위한 다양한 함수들이 있습니다. 그 중에서도 PHP mcrypt 라이브러리 함수는 복호화까지 가능한 암호화 라이브러리입니다. 이 글에서 소개하는 소스코드는 제가 직접 작성한 것으로, PHP의 mcrypt 라이브러리 함수를 활용하여 암호화와 복호화를 구현한 클래스 소스코드입니다. 다른 웹 프로그램을 만들다가 급하게 만든 초기 버전이기 때문에 웹프로그래밍의 고수 분들이 보시기에는 허술한 부분이 많이 있을 것입니다. 하지만 저는 이 예제 소스코드가 암호화의 기본적인 틀이 어떻게 구성되어 있는가를 알아볼 수 있는 매우 좋은 예제가 될 수 있을 것이라 생각합니다.


PHP의 Mcrypt 라이브러리


PHP에서 사용할 수 있는 암호화 라이브러리는 매우 많습니다. Mcrypt 라이브러리는 그 중 하나에 해당되는 라이브러리입니다. 일반적으로 웹 프로그래밍에서 자주 사용되는 암호화 기술들은 복호화가 불가능한 것들이 많습니다. PHP에서 암호화를 할 때 자주 사용되는 md5() 함수라든지 MySQL의 password() 함수는 모두 복호화가 불가능한 암호화 알고리즘입니다.

복호화가 불가능한 암호화 알고리즘은 주로 패스워드를 암호화할 때 사용됩니다. 왜냐하면 패스워드는 복호화를 해야 하는 필요성이 없는 매우 민감한 개인 정보이기 때문입니다. 로그인 처리를 할 때에는 사용자가 입력한 패스워드를 암호화 한 후에 데이터베이스에 저장된 암호화된 패스워드와의 일치 여부만 확인하면 됩니다. 패스워드는 복호화가 되지 않으므로, 사이트 관리자도 사용자의 패스워드를 알 수 없습니다. 따라서 사용자가 패스워드를 분실했을 때에는 사이트 관리자가 패스워드를 알려주는 것이 아니라 해당 사용자의 패스워드 초기화 하는 것입니다.

하지만 Mcrypt 라이브러리는 복호화가 가능한 암호화 라이브러리입니다. 데이터를 암호화 했다가 다시 복호화하여 원본 데이터를 그대로 확인할 수 있는 것이죠. 관리자 이외의 사람들이 보면 안 되는 보안이 필요한 데이터를 일반 파일이나 데이터베이스에 저장할 때 Mcrypt 라이브러리를 활용하면 됩니다. 이렇게 암호화된 데이터는 나중에 다시 사용될 수 있으니, 웹 프로그램의 설정 파일이나 기본 데이터 파일 등을 안전하게 저장할 필요성이 있을 때 Mcrypt 라이브러리를 사용하면 매우 좋습니다. 이 글에서 소개하는 암호화/복호화 소스코드는 Mcrypt 라이브러리를 활용한 소스코드입니다.

암호화/복호화 클래스 소스코드


저는 Mcrypt 라이브러리를 활용하여 다음과 같은 소스코드를 만들어보았습니다. 이 소스코드는 암호화와 복호화를 매우 간단하게 구현해주는 클래스 소스코드입니다. 그냥 자신이 현재 개발하고 있는 웹 프로그래밍 프로젝트에 아래의 소스코드를 포함하고 있는 파일만 require 하면 바로 사용할 수 있습니다. 클래스로 구현하였기 때문에 타 소스와의 충돌이 전혀 발생하지 않습니다. 또한 싱글톤 패턴으로 작성되었기 때문에 프로젝트 내에서 단 한 번만 불러오면 되므로 사용할 때에도 매우 편리합니다.

암호화 또는 복호화를 하려면 이 클래스를 프로젝트에 require 한 후에 encrypt() 메소드와 decrypt() 메소드를 사용하면 됩니다. 클래스 소스코드 중간에서 볼 수 있는 setIv() 메소드는 Mcrypt 라이브러리에서 암호화를 할 때 꼭 필요한 IV 값을 생성하는 메소드입니다. 이 메소드는 이 클래스를 로드할 때에만 딱 한 번 실행되어야 합니다. 그 이후에는 이 메소드를 다시 실행하지 않아도 정상적으로 암호화 또는 복호화할 수 있습니다. 만약 좀 더 편리하게 클래스를 수정하고 싶다면, setIV() 메소드를 __construct() 메소드에 포함시켜도 됩니다.

※ 사용 예제는 소스코드 하단에 있습니다.

final class EES {

    protected static $_instance = NULL;
    protected $_key_size = NULL;
    protected $_key = NULL;
    protected $_iv = NULL;
    protected $_iv_size = NULL;
    protected $_fixed_iv = NULL;
    
    protected function __construct ()
    {
        $this->_key = pack('c*', base64_encode('http://www.erzsamatory.net'));
        $this->_key_size = strlen($this->_key);
        $this->_fixed_iv = base64_decode('pZxBk2nYByDM0H7NqhvIlPnVgc2yDTHiDGlV2T69uhE=');
    }
    
    public static function getInstance ()
    {
        if (self::$_instance === NULL) {
            self::$_instance = new self();
        }
        
        return self::$_instance;
    }
    
    public function setIv ($iv = '')
    {
        if (!$iv) {
            $this->_iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
            $this->_iv = mcrypt_create_iv($this->_iv_size, MCRYPT_RAND);
        } else {
            $this->_iv = base64_decode($iv);
        }
        
        return $this;
    }
    
    public function encrypt ($text)
    {
        $temp = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->_key, $text, MCRYPT_MODE_CBC, $this->_iv);
        $temp = serialize(array($temp, $this->_iv));
        $temp = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->_key, $temp, MCRYPT_MODE_CBC, $this->_fixed_iv);
        return $temp;
    }
    
    public function decrypt ($encrypted_text)
    {
        $temp = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->_key,
                        $encrypted_text, MCRYPT_MODE_CBC, $this->_fixed_iv);
        $temp = unserialize($temp);
        $temp = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->_key, $temp[0], MCRYPT_MODE_CBC, $temp[1]);
        return $temp;
    }
}


require_once 'EES.class.php';
echo ($encrypted = EES::getInstance()->setIv()->encrypt('안녕하세요? 황민식입니다.')).'<br />';
echo EES::getInstance()->decrypt($encrypted);


※ 위의 소스코드는 개발중인 소스코드이기 때문에 오류가 발생할 수 있습니다. 이 점 꼭 유의해주시기 바랍니다.
http://www.erzsamatory.net/trackback/16

건전한 댓글 문화를 만들어주시기 바랍니다 ^^
불건전한 댓글이 등록되는 경우 관리자의 임의적 판단으로 삭제될 수 있음을 미리 공지드립니다.

비밀글로 작성하기