Tistory View

openssl

복호화(PHP) : aes256 cbc openssl

God Dangchy What should I do? 2020. 3. 23. 18:21

이전에 포스트한 (C/C++)버전의 PHP버전이다.


하지만 이글을 바로 읽는 독자가 있을 수 있으니... 





명령줄에서 다음과 같이 암호화 작업을 했다면


openssl enc -e -aes-256-cbc -in plain.txt -out encrypted.data -k "my_password"

이렇게 생성된 파일을 복호화하는 코드를 작성해 보자.


실제 위의 명령줄은 문제가 많지만, 처음 openssl을 접하는 사용자는 위의 명령을 통해 암호화작업을 많이 하게 될 것이다. 그러다 보니, 이 문제많은 방식에서 다른 방식으로 변경할 경우 일단 복호화작업을 해야 하니, 복호화 프로그래밍도 익힐 겸 복호화하는 코드를 생성해보자.



저장된 파일의 구조는 이전 포스트에서도 언급했듯이 다음의 구조를 가진다.



검은색 부분에 "Salt__"(8bytes)가 있으며, 이어서 실제 Salt값(노란색)이 8bytes가 따라온다.

그 다음 빨간색부분이 암호화된 데이터이다.





문제는 PHP에는 EVP_BytesToKey함수가 없다. 어쩔 수 없이, 온 세상을 뒤져보았지만, 찾긴 찾았는데... 그냥 만들어 쓰기로 했다.


PHP용 EVP_BytesToKey

function EVP_BytesToKey( $digest, $salt, $pass, $count, $keySize, $ivSize )

{

$reqSize = $keySize + $ivSize;

if( !$salt ) {

$salt = '';

}

$mall = '';


$pass .= $salt;


$mi = hash($digest, $pass, true);

for( $i = 1 ; $i < $count ; $i++ ) {

$mi = hash( $digest, $mi . $pass, true );

}

$mall = $mi;

while( strlen( $mall) < $reqSize )

{

$m2 = hash( $digest, $mi . $pass, true );

for( $i = 1 ; $i < $count ; $i++ ) {

$m2 = hash( $digest, $m2 . $pass, true );

}

$mall .= $m2;

$mi = $m2;

}

return array( 'key' => substr( $mall, 0, $keySize ), 'iv' => substr( $mall, $keySize, $ivSize ) );

}



나름 필자가 열심히 만들었는데.. 테스트를 하긴 했는 데, 솔직히 자신은없다..;;;;


이 함수를 호출하는 예제코드는 다음과 같다.

$keyiv = EVP_BytesToKey( 'sha256', $salt, "password", 1, 32, 16 );

echo 'key =', bin2hex( $keyiv['key'] ), "\n";

echo 'iv  =', bin2hex( $keyiv['iv']  ), "\n";

aes-256-cbc를 이용하기 때문에 key길이는 32, iv길이는 16을 넘겨 주었다.





다음의 함수는 이 암호화된 파일의 내용(파일이 아니고) 복호화하는 함수이다.

리턴값은 성공시 복호화된 데이터이며, 실패시에는 NULL을 반환한다.



function decrypt_def_openssl_encoded_content( $encrypted, $password, $iter )

{

$salt = '';


       // salt때문에 크기는 16바이트보다 클 수밖에 없다.

if( strlen( $encrypted ) < 16 ) {

echo "file is too short < 16 bytes\n";

return NULL;

}

// salt값을 빼온다.

// "Salt__"라는 signature를 체크하는 부분은 생략했다.

$salt = substr( $encrypted, 8, 8 );

// salt와 넘어온 비밀번호로 key와 iv를 추출한다.

// 여기서는 md(message digest)로 sha256을 사용하지만, 구버전에서 만들어진 파일을 풀려면, md5를 넘겨야한다.

$keyiv = EVP_BytesToKey( 'sha256', salt, $password, $iter, 32,16 ) );

if( !$keyiv ) {

echo "extract key and iv failure\n";

return NULL;

}

return openssl_decrypt( substr( $encrypted, 16), 'AES-256-CBC', $keyiv['key'], OPENSSL_RAW_DATA, $keyiv['iv'] );

}



파일을 복호화

// count 값으로 1을 넣었는 데, 이는 openssl명령이 이 값을 1로 처리하고 있어서다.

echo decrypt_def_openssl_encoded_content( file_get_contents('파일이름'), '비밀번호', 1 );




만약 -iter 나 -pbkdf2 를 지정하였다면 위의 EVP_BytesToKey함수 대신에 다음과 같이 적절히 교체해서 사용하면 된다.


$keyiv = openssl_pbkdf2 ( $password , $salt , 32 + 16, $iter, 'sha256'  );

$key = substr( $keyiv, 0, 32 );

$iv   = substr( $keyiv, 32, 16 );


기본 openssl명령은 openssl_pbkdf2함수를 이용해서 한번에 key와 iv를 만들어 나눠서 사용하고 있다.






'openssl' 카테고리의 다른 글

복호화(PHP) : aes256 cbc openssl  (2) 2020.03.23
복호화(C/C++) : aes256 cbc openssl  (0) 2020.03.23
명령줄 : aes256 cbc openssl  (0) 2020.03.23
Replies
Reply Write