<?PHP
/**
 * RSA 클래스
 * @package	SmileSERV
 * @author	솔루션개발팀
 * @since	2015년 01월 27일
 * @see		RSA 암/복호화 작업을 위한 클래스
 */
class ssRsa
{
	/**
	 * @var	키 생성에 사용되는 비밀번호로, 평문화된 개인키를 리소스로 전환하거나 공개키 추출 시 사용된다.
	 */
	private $password ;
	
	/**
	 * @var	RSA 키 정보 ( 1차 연관 배열로 구성되며, 키 값은 private, public 이다 )
	 */
	private $key ;
	
	
	/**
	 * 클래스 생성자, OpenSSL 설치 여부를 확인한다.
	 * @return	Void
	 * @see		OPENSSL_VERSION_TEXT 상수는 PHP 5.2.0 버전부터 추가된 상수이므로 PHP 버전이 낮다면 상수가 없을 수 있다.
	 * 			그러므로, OpenSSL 설치 여부가 확실하다면 본 검사는 생략되어도 무방하다.
	 */
	public function __construct ()
	{
		if ( ! defined ( 'OPENSSL_VERSION_TEXT' ) || ! preg_match ( '/OpenSSL/' , OPENSSL_VERSION_TEXT ) )
			$this->error ( 'OpenSSL 확장이 설치되지 않았습니다. 서버 관리자에게 문의하여 주십시오.' ) ;
	}
		
	
	/**
	 * RSA 암호화
	 * @param	String	$plain					암호화 대상 문자열
	 * @param	Boolean	$base64		[optional]	Base64 인코딩 여부 ( 기본 값 : true )
	 * @param	Boolean	$compress	[optional]	GZ 압축 여부 ( 기본 값 : false )
	 * @return	String							암호화된 문자열
	 */
	public function encrypt ( $plain , $base64 = true , $compress = false )
	{
	    // 용량 절감과 보안 향상을 위해 평문을 압축한다.
	    if ( $compress )
	    	$plain	= gzcompress ( $plain ) ;
	    
	    // 공개키를 리소스로 전환한다.
	    $public	= openssl_pkey_get_public ( $this->key['public'] ) ;
		if ( ! is_resource ( $public ) )
			$this->error ( '공개키 리소스 전환하에 실패하였습니다.' ) ;
	    
		// 공개키 리소스를 이용하여 평문을 암호화한다.
	    if ( ! openssl_public_encrypt ( $plain , $encrypt , $public ) )
			$this->error ( '공개키를 이용한 암호화에 실패하였습니다.' ) ;
			
		// 공개키 리소스 해제
		openssl_pkey_free ( $public ) ;
	    
	    // 암호문을  Base64로 인코딩하여 반환한다.
	    return $base64 ? base64_encode ( $encrypt ) : $encrypt ;
	}
	
	
	/**
	 * RSA 복호화
	 * @param	String	$plain					복호화 대상 문자열
	 * @param	Boolean	$base64		[optional]	Base64 인코딩 여부 ( 기본 값 : true )
	 * @param	String	$compress	[optional]	GZ 압축 여부 ( 기본 값 : false )
	 * @return	String							복호화된 문자열
	 */	
	public function decrypt ( $encrypt , $base64 = true , $compress = false )
	{
	    // 암호문을 Base64로 디코딩한다.
		if ( $base64 )	    
	    	$encrypt	= base64_decode ( $encrypt , true ) ;
	    if ( $encrypt === false )
			return false ;
	    
	    // 개인키를 리소스로 전환한다.
	    $private	= openssl_pkey_get_private ( $this->key['private'] , $this->password ) ;
		if ( ! is_resource ( $private ) )
			$this->error ( '개인키 리소스 전환에 실패하였습니다.' ) ;
	    
		// 개인키 리소스를 사용하여 복호화한다.
	    if ( ! openssl_private_decrypt ( $encrypt , $plain , $private ) )
			$this->error ( '개인키를 이용한 복호화에 실패하였습니다.' ) ;
		
		// 개인키 리소스 해제
		openssl_pkey_free ( $private ) ;
	    
	    // 평문 압축을 해제한다.
	    return $compress ? gzuncompress ( $plain ) : $plain ;
	}	
	
	
	/**
	 * 키를 생성한다.
	 * @param	Integer	$bit		[optional]	비트 ( 기본 값 : 1024 )
	 * @param	String	$algorithm	[optional]	키 생성 알고리즘 ( 기본 값 : sha256 )
	 * @return	Array							RSA 키 정보가 담긴 1차 연관 배열
	 */
	public function makeKey ( $bit = 1024 , $algorithm = 'sha256' )
	{
		// 키를 생성한다.
	    $key	= openssl_pkey_new
		(
			array
			(
	        	'digest_alg'		=> $algorithm ,
	        	'private_key_bits'	=> $bit ,
	        	'private_key_type'	=> OPENSSL_KEYTYPE_RSA ,
	    	)
		) ;
		
		// 키 생성이 정상적으로 이뤄졌는지 확인한다.
		if ( ! is_resource ( $key ) )
			$this->error ( '키 생성에 실패했습니다.' ) ;
		
		// 개인키를 추출한다.	
	    if ( ! openssl_pkey_export ( $key , $private , $this->password ) )
			$this->error ( '개인키 추출에 실패했습니다.' ) ;
	    
		// 공개키를 추출한다.
	    $public = openssl_pkey_get_details ( $key ) ;
	    
		// 키를 할당하고, 결과로 반환한다.
		$this->setKey ( $private , $public['key'] ) ;
		return $this->key ;
	}
	
	
	/**
	 * 암호를 할당한다.
	 * @param	String	$password	암호
	 * @return	Void
	 */
	public function setPassword ( $password )
	{
		$this->password	= $password ;
	}
	
	
	/**
	 * 키를 할당한다.
	 * @param	String	$private	개인키
	 * @param	String	$public		공개키
	 * @return	Void
	 * @see		기존에 만들어놓은 키가 있는 경우, 키를 재생성하지 않고 할당하여 사용하기 위한 메소드.
	 */
	public function setKey ( $private , $public )
	{
		$this->key	= array
		(
			'private'	=> $private ,
			'public'	=> $public ,
		) ;
	}
	
	
	/**
	 * 키를 반환한다.
	 * @return	Array	RSA 키 정보가 담긴 1차 연관 배열
	 */
	public function getKey ()
	{
		return $this->key ;
	}
	
	
	/**
	 * 에러 메세지를 출력한다.
	 * @param	String	$message	에러 메시지
	 * @return	Void
	 */
	public function error ( $message )
	{
		echo $message ;
		exit () ;
	}
}
?>