암호화/복호화시에 생성되는 padding 문자 제거 방법

다양한 암호화 방법에 대하여 공부중이다.  AES, DES 는 현재는 그리잘 쓰이지 않는 방법이지만 미국에서 표준암호화 방법으로 채택된 것이어서 MySql에도 quary문에서 직접 적용이 가능한 함수를 가지고 있다.

(‘text’,’key’), AES_DECRYPT(‘text’,’key’) 함수를 php에서 연동하여 사용하는 방법을 연습해 보기 위해 구글링하여 테스트해보았다. 대부분의 코드가 대동소이하다.
암호화 코드는 아래와 같다.

function ($val){
  $new_key = str_repeat(chr(0), 16);
  for($i=0;$i<strlen($key);$i++){ 
	$new_key[$i%16] = chr(ord($new_key[$i%16]) ^ ord($key[$i]));
  }
$key=$new_key;
  $pad_value = 16-(strlen($val) % 16);
  $val = str_pad($val, (16*(floor(strlen($val) / 16)+1)), chr($pad_value)); 
  $cipher= mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $val, MCRYPT_MODE_ECB, mcrypt_create_iv( mcrypt_get_ivSize,  MCRYPT_DEV_URANDOM));
  return $cipher;
}

AES는 ECB모드를 이용하는 것으로 블럭 크기가 16비트이다. 따라서 암호키와 함호화할 대상 택스트의 크기를 모두 16의 배수로 조정해야 한다. 그런 후에 의 MCRYPT 함수를 불러서 암호화하면 끝…코드를 살펴보면 초기화벡터(iv, initialize vector)를 사용하고있지만 ECB모드를 암호화에 키값만 필요하기 때문에 불필요한 값이다.
따라서 mcrypt_create_iv() 이 부분은 ‘ ‘ 이렇게 공란으로 처리해도 무방하다.  오히려 처리속도만 지연되는 불필요한 값이라고 생각된다.

 function AES_decrypt($val){
    $new_key = str_repeat(chr(0), 16);
    for($i=0;$i<strlen($key);$i++){ 
	$new_key[$i%16] = chr(ord($new_key[$i%16]) ^ ord($key[$i]));
    }
    $val = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $val, MCRYPT_MODE_ECB, mcrypt_create_iv( $this->MY_ivSize, MCRYPT_DEV_URANDOM) );
    return rtrim($val, "..16");
}

여기서 문제가 발생했다.
Warning: rtrim(): Invalid ‘..’-range, no character to the left of ‘..’ in
이런 오류가 뜬다. 구글링해서 다른 몇몇 사이트를 살펴보고 최종적으로 에러가 뜨지않는 것을 찾아냈다.
return rtrim($val, “\0..\16”); 이렇게 바꾸는 것이다.
하지만 며칠 후에 우연히 복호화 된 텍스트를 16진수로 바꾸어 보았더니..
뒤쪽이 ‘…1010101010’ 이런 식으로 끝난다. padding이 제거 되지 않은 것이다.
암호화코드와 복호화 코드를 꼼꼼이 비교해보니 원인을 알수있었다. 암호화할 때는 택스트의 길이를 16의 배수가 되게 하기위해 16으로 나눈 나머지 숫자를 $pad_value라고 정의 하고 이것을 16진수라고 가정해서 일반 스트링으로 바꿔서 붙여 놓고 (아마도 16진수에서 0-16까지는 택스트로는 특별한 값을 나타내지 않는 것이기 때문에이렇게 하는것이라고 생각된다. )
제거할땐 그냥 “\0..\16″이런 식으로 표현했으니 이것은 그냥 숫자 0과 16에 불과하기 때문에 padding이 제거되지않은것이다. 그래서 이걸 0–>chr(0) 이런 식으로 바꾸어 보았지만 효과가 없다.
할 수 없이 unpadding 함수를 만들어 넣기로 했다.

while(  0 < hexdec(bin2hex(substr($val,strlen($val)-1))) && hexdec(bin2hex(substr($val,strlen($val)-1))) <= 16 ){
	$val=substr($val,0,strlen($val)-1); 
}

텍스트의 가장 끝에 있는 스트링을 16진수로 바꾸어서 그 값이 0과 16사이에 있으면 그걸 제거하는 로직이다.
여기서 잠시 실수할 수도 있는 것이 16진수를 다시 십진수로 변환하는 것과 끝자리 제거시
$val=substr($val,0,strlen($val)-2);
이렇게 하지말아야 한다는 것이다.
처음에는 이 두가지를 모두 간과하고 부등호의 판단이 16진수의 알파벳을 무시하고 숫자만을 가지고 판단하기 때문에 지우지말아야할 것을 몇개 더 지우는 것이라고 생각해서
is_numeric(bin2hex(substr($val,strlen($val)-1))) && 이런걸 앞에 넣었었다. ㅋ

이해가 안되는 사항이지만 여기 적용된 encrypt 함수에서 padding처리는 택스트 길이가 16일때도 $pad_value=16 이라는 값으로 패딩이 16개 추가되기 때문에 앞의 while 문에서 등호를 반드시 포함해야 한다.

MySql함수와 완벽한 호환성이 검증되기 전까지는 아직 완전하다고 볼 수는 없지만 일단 기록으로 남긴다.

소셜댓글

Loading Disqus Comments ...
Loading Facebook Comments ...

One thought on “암호화/복호화시에 생성되는 padding 문자 제거 방법”

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다

이 사이트는 스팸을 줄이는 아키스밋을 사용합니다. 댓글이 어떻게 처리되는지 알아보십시오.