C#, PHP – RIJNDAEL 256bit 암/복호화

C#과 php간에 데이터를 주고 받아야 하는데
평문으로 통신하기에 무리가 있던 도중
기존에 사용하던 php 암호화 라이브러리와 연동되는 c# 코드를 발견~
살짝 수정해서 사용하는데 무리가 없음

기본은 128bit지만 256bit로 변경했음
php의 경우 블록에서 남는 부분을 zero로 채워넣기 때문에
c#에서 PaddingMode.Zeros를 설정해야 정상적으로 동작합니다.

Encryption.cs

[csharp]
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace TestClass
{
class Encryption
{
private static byte[] rijnKey = Encoding.UTF8.GetBytes("abcdefg_abcdefg_abcdefg_abcdefg_");
private static byte[] rijnIV = Encoding.UTF8.GetBytes("abcdefg_abcdefg_abcdefg_abcdefg_");

public static String EncryptIt(String s)
{
String result;
RijndaelManaged rijn = new RijndaelManaged();
rijn.Mode = CipherMode.CBC;
rijn.Padding = PaddingMode.Zeros; // php와의 연동에서 꼭 확인
rijn.BlockSize = 256;

using (MemoryStream msEncrypt = new MemoryStream())
{
using (ICryptoTransform encryptor = rijn.CreateEncryptor(rijnKey, rijnIV))
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(s);
}
}
}
result = Convert.ToBase64String(msEncrypt.ToArray());
}
rijn.Clear();

result = Base64UrlEncode(result);

return result;
}

public static String DecryptIt(String s)
{
String result;
RijndaelManaged rijn = new RijndaelManaged();
rijn.Mode = CipherMode.CBC;
rijn.Padding = PaddingMode.Zeros;
rijn.BlockSize = 256;

s = Base64UrlDecode(s);

using (MemoryStream msDecrypt = new MemoryStream(Convert.FromBase64String(s)))
{
using (ICryptoTransform decryptor = rijn.CreateDecryptor(rijnKey, rijnIV))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader swDecrypt = new StreamReader(csDecrypt))
{
result = swDecrypt.ReadToEnd();
}
}
}
}
rijn.Clear();

return result;
}

public static string Base64UrlEncode(string arg)
{
arg = arg.Split(‘=’)[0]; // Remove any trailing ‘=’s
arg = arg.Replace(‘+’, ‘-‘); // 62nd char of encoding
arg = arg.Replace(‘/’, ‘_’); // 63rd char of encoding
return arg;
}

public static string Base64UrlDecode(string arg)
{
string s = arg;
s = s.Replace(‘-‘, ‘+’); // 62nd char of encoding
s = s.Replace(‘_’, ‘/’); // 63rd char of encoding
switch (s.Length % 4) // Pad with trailing ‘=’s
{
case 0: break; // No pad chars in this case
case 2: s += "=="; break; // Two pad chars
case 3: s += "="; break; // One pad char
default:
throw new System.Exception("Illegal base64url string!");
}
return s;
}
}
}

[/csharp]

test.php

[php]
//Encryption function
function encryption($encrypt, $key, $iv)
{
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_256, ”, MCRYPT_MODE_CBC, ”);
mcrypt_generic_init($td, $key, $iv);
$encrypted = mcrypt_generic($td, $encrypt);
$encode = base64_encode($encrypted);
$encode = base64safeEncode($encode);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);

return $encode;
}

//Decryption function
function decryption($decrypt, $key, $iv)
{
$decoded = base64safeDecode($decrypt);
$decoded = base64_decode($decoded);
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_256, ”, MCRYPT_MODE_CBC, ”);
mcrypt_generic_init($td, $key, $iv);
$decrypted = mdecrypt_generic($td, $decoded);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);

return trim($decrypted);
}

function base64safeEncode($data) {
$data = str_replace("=", "", $data);
$data = str_replace("+", "-", $data);
$data = str_replace("/", "_", $data);
return $data;
}

function base64safeDecode($data) {
$data = str_replace("-", "+", $data);
$data = str_replace("_", "/", $data);

switch (strlen($data) % 4) {
case 0: break;
case 2: $data .= "=="; break;
case 3: $data .= "="; break;
}

return $data;
}

$key = "abcdefg_abcdefg_abcdefg_abcdefg_";
$iv = "abcdefg_abcdefg_abcdefg_abcdefg_";

echo encryption("Hello world!", $key, $iv);
echo decryption("1ERpu8RaiyMqsXdjhCEu9IVMyQlz/A3fBR6vGbNxaVs=", $key, $iv);
[/php]

screw 로 php 소스코드 암호화

php_screw 설치

php_screw 설치하기를 참고하여 php_screw.so를 익스텐션에 올린다

 

screw 컴파일

php_screw 소스를 압축해제한 디렉토리에 tools가 있다
cd tools
make

screw 컴파일

실행파일을 접근가능한 디렉토리로 복사해준다. 여기서는 /usr/bin/ 으로 복사했다
cp screw /usr/bin

 

php 파일 암호화

테스트할 파일을 만든다
echo "" > phpinfo.php

암호화한다
screw phpinfo.php

php_screw

위에처럼 phpinfo.php, phpinfo.php.screw 파일이 생성된다
phpinfo.php 는 암호화 되었고
phpinfo.php.screw 는 원본파일이다

php_screw 를 활용한 php 소스 코드 암호화하는 방법

0. 환경

운영체제 Ubuntu 12.04 LTS (우분투 설치 안내)
php설치
apt-get install php5 php5-dev php-common

 

1. 소스코드 다운로드

http://sourceforge.net/projects/php-screw/files/

캡처

최신버전을 다운로드 하는데,
본글에서는 screw 1.5버전을 기준으로 설명되었습니다.

[php_screw-1.5.tar.gz]
http://sourceforge.net/projects/php-screw/files/latest/download?source=files

 

2. 서버에서 screw 를 다운로드하고 압축을 해제합니다.

wget http://sourceforge.net/projects/php-screw/files/latest/download?source=files
tar xfzp php_screw-1.5.tar.gz
cd php_screw-1.5

 

3. my_screw.h 수정

SEED를 변경합니다.
screw 에서 키값은 암호화/복호화시 사용되므로 아주 중요합니다.
암호화시 사용한 SEED를 이용해 복호화를 하므로 SEED가 다른 소스로 암호화된 소스는 처리가 안됩니다.
vim my_screw.h

short pm9screw_mycryptkey[] = {
11152, 368, 192, 1281, 62
};

적절하게 아래처럼 변경(아래처럼 변수를 늘려도 됨)

short pm9screw_mycryptkey[] = {
12311, 312, 4422, 534, 11, 849, 125
};

 

4. 컴파일

phpize
./configure
make
make install

4.1 컴파일 오류
/usr/local/src/php_screw-1.5/php_screw.c:124:2: error: 'struct _zend_compiler_globals' has no member named 'extended_info'
/usr/local/src/php_screw-1.5/php_screw.c: In function 'zm_shutdown_php_screw':
/usr/local/src/php_screw-1.5/php_screw.c:133:2: error: 'struct _zend_compiler_globals' has no member named 'extended_info'
/usr/local/src/php_screw-1.5/php_screw.c: In function 'pm9screw_compile_file':
/usr/local/src/php_screw-1.5/php_screw.c:81:7: warning: ignoring return value of 'fread', declared with attribute warn_unused_result [-Wunused-result]
/usr/local/src/php_screw-1.5/php_screw.c: In function 'pm9screw_ext_fopen':
/usr/local/src/php_screw-1.5/php_screw.c:36:7: warning: ignoring return value of 'fread', declared with attribute warn_unused_result [-Wunused-result]
make: *** [php_screw.lo] Error 1

위와 같은 오류가 발생할 경우 php_screw.c 파일의 마지막줄에 CG(extended_info) = 1; 줄을 주석처리해준다

PHP_MINIT_FUNCTION(php_screw)
{
//CG(extended_info) = 1;
org_compile_file = zend_compile_file;
zend_compile_file = pm9screw_compile_file;
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(php_screw)
{
//CG(extended_info) = 1;
zend_compile_file = org_compile_file;
return SUCCESS;
}

 

4. so 파일 복사

php5 extension 모듈이 있는 폴더에 복사해준다
cp modules/php_screw.so /usr/lib/php5/20100525/

extension 모듈 디렉토리 위치를 모르는 경우 아래와 같이 확인을 할 수 있다
php -i | grep extension_dir

 

5. php.ini에 php_screw.so 추가

cd /etc/php5/mods-available
echo "extension=php_screw.so" > screw.ini
cd /etc/php5/conf.d
ls -s ../mods-available/screw.ini 90-screw.ini

상황에 따라서 php.ini 파일에 직접 extension=php_screw.so 를 적어주어도 된다.

 

6. apache 웹서버 재시작

/etc/init.d/apache2 restart

 

7. screw 설치확인

php -i | grep screw

php_screw 설치확인

정규식 테스트

<?
 /**
  * 정규식 테스트
  * PHPSCHOOL TIP&TECH 게시판 제목만 가져오기
  */


 // 게시판 글 가져오기
 $fp = fopen(“http://phpschool.com/gnuboard4/bbs/board.php?bo_table=tipntech&page=1“, “r”);
 while(!feof($fp)) {
  $str .= fgets($fp, 1024);
 }
 fclose($fp);


 // 제목부분만 $matches에 저장
 preg_match_all(“/(<span style=”)(.*)(<\/span>)/”, $str, $matches);
 
 // 필요없는 부분 제거
 $tmp = str_replace(“<span style=”>”, “”, $matches[0]);
 $tmp = preg_replace(“/(<\/span>)(.*)/”, “”, $tmp);


 // 출력하면서 영문,숫자부분에 링크
 foreach($tmp as $v) {
  echo preg_replace(“/([A-Za-z0-9]([A-Za-z0-9]*)[A-Za-z0-9])/”, “<a href=’$1′>$1</a>”, $v).”<BR>”;
 }
?>

php 5.2.5

php 5.2.5

./configure \
–prefix=/usr/local/php \
–with-apxs2=/usr/local/apache2/bin/apxs \
–with-mysql=/usr/local/mysql/ \
–with-config-file-path=/usr/local/php/conf \
–with-png-dir=/usr/local/libpng \
–with-jpeg-dir=/usr/local/bin \
–with-zlib \
–with-gd \
–with-freetype-dir=/usr \
–enable-magic-quotes \
–enable-sockets \
–disable-debug \
–enable-mbstring \
–enable-soap \
–enable-ftp