PHP Crypter dengan Passphrase Key

Simple PHP program untuk encode dan decode data menggunakan passphrase dengan Rijndael 256 bit encryption.

Minggu lalu ceritanya iseng2 bikin script buat encrypt file. Nah karena keterbatasan waktu, ane belom sempet utak atik lagi. Inspirasinya dari PGP yang pake pertukaran public key, bedanya ini pertukarannya pake passphrase keynya. Mungkin ada yg berminat buat ngembangin.

  • Tool Name : PHP Crypter
  • Program Language : PHP
  • Environment : CLI
  • Tested On : PHP 5.4.4 (built: Jun 13 2012)
  • Linux Requirement : PHP mcrypt library
  • Description : Encode or decode data using specific key passphrase with Rijndael256 bit encryption.
  • Repo: https://github.com/ditatompel/PHP-Crypter.
  1<?php
  2/**
  3 * PHP Crypter
  4 * 
  5 * This program used to encode or decode data using specific key passphrase
  6 * with Rijndael 256 bit encryption.
  7 * 
  8 * Still very early release, just for fun coding purpose :)
  9 *
 10 * LICENSE :
 11 * This program is free software; you can redistribute it and/or modify it
 12 * under the terms of the GNU General Public License version 2 as published by
 13 * the Free Software Foundation.
 14 * This program is distributed in the hope that it will be useful, but WITHOUT
 15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 17 * more details.
 18 * 
 19 * @author Christian Ditaputratama <[email protected]>
 20 * 
 21 * Usage : 
 22 * new phpCrypter($argv);
 23 */
 24
 25
 26
 27class phpCrypter
 28{
 29    const V = 0.01; // this is the program version
 30    const PASSPHARSE = "di7atomp3l"; // change this
 31    const EXT = '.tpl'; // file extention result
 32    private $verbose = FALSE; // verbose mode. Default false = off
 33    private $decrypt = FALSE; // default mode = encrypt
 34    private $key = NULL; // property for custom key or use PASSPHARSE constant
 35    
 36    /* Contructor. Set up arguments, print banner and execute main program. */
 37    function __construct($opts) {
 38        $cmd = $this->arguments($opts);
 39        print $this->banner();
 40        
 41        /**
 42         * Required parameter is "d" for decrypt OR "e" for encrypt.
 43         * Stop the program if both option has been set.
 44         */
 45        if ( array_key_exists('d', $cmd) && array_key_exists('e', $cmd) ) {
 46            print "\n" . $this->crot("[!] Double method, please choose 1 beetween decrypt / encrypt", 'red') . "\n";
 47            print $this->usage($cmd['input'][0]);
 48            exit;
 49        }
 50        
 51        /* Print help screen then exit if file param is not set */
 52        if ( !array_key_exists('file', $cmd) ) {
 53            print $this->usage($cmd['input'][0]);
 54            exit;
 55        }
 56        
 57        if ( array_key_exists('d', $cmd) ) $this->decrypt = TRUE;
 58        if ( array_key_exists('v', $cmd) ) $this->verbose = TRUE;
 59        
 60        if ( array_key_exists('key', $cmd) ) $this->key = is_null ($cmd['key']) ? self::PASSPHARSE :  $cmd['key'];
 61        else $this->key = self::PASSPHARSE;
 62        
 63        if ( $this->cekData($cmd['file']) ) {
 64            if ( !array_key_exists('o', $cmd) )
 65                print "\n" . $this->crypter($this->readData($cmd['file']));
 66            else
 67                $this->writeData($cmd['file'] . self::EXT, $this->crypter($this->readData($cmd['file'])));
 68        }
 69        else
 70            print $this->crot(" [!] Data is not exist or is not wirtable!", 'red') . "\n";
 71    }
 72    
 73    /**
 74     * The cool banner
 75     * @return string
 76     */
 77    function banner() {
 78        $msg = " ________________________________________________________\n";
 79        $msg .= "|         mm                                             |\n";
 80        $msg .= "|      /^(  )^\   PHP Crypter " .  $this->crot('v' . self::V,'cyan') . "                      |\n";
 81        $msg .= "|      \,(..),/   Encode / decode data using specific    |\n";
 82        $msg .= "|        V~~V     key passphrase with " .  $this->crot('Rijndael 256','red') . " bit   |\n";
 83        $msg .= "|      encryption. Coded by [email protected]    |\n";
 84        $msg .= "|________________________________________________________|\n\n";
 85        return $msg;
 86    }
 87    
 88    /**
 89     * Help Screen
 90     * @return string
 91     */
 92    function usage($file) {
 93        $msg = "\nUsage : ";
 94        $msg .= $file . " --file=[file] [option(s)]\n";
 95        $msg .= "Example : ";
 96        $msg .= $file . " --file=/home/dit/private.txt --key=\"RAHASIA\" -dvo\n";
 97        $msg .= "Option(s) :\n";
 98        $msg .= " -d : Decrypt | -e : Encrypt (required)\n";
 99        $msg .= " --key=[key] : passphrase key to encrypt / decrypt file\n";
100        $msg .= " -v : verbose mode, print all output to terminal\n";
101        $msg .= " -o : write output to [file].tpl\n";
102        return $msg;
103    }
104    
105    /**
106     * The Crypter
107     * Encrypt / Decrypt the data using PHP mcrypt rinjadael 256 ECB mode.
108     * @return string
109     */
110    function crypter($str=NULL) {
111        // notify user if the program cannot encrypt/decrypt empty string
112        if( is_null($str) ) {
113            print $this->crot(" [!] Cannot encrypt/decrypt null string", 'red') . "\n";
114            return $str;
115        }
116        
117        $mode = 'encrypt';
118        if ( $this->decrypt ) $mode = 'decrypt';
119        if ( $this->verbose ) {
120            print " [*] Trying to " . $this->crot($mode, 'purple') . " file...\n";
121            print " [+] Using " . $this->crot($this->key,'l_cyan') . " as passpharse key\n";
122        }
123        $data = NULL;
124        $header = "-----BEGIN PHP CRYPTER BLOCK-----\n";
125        $header .= "Version: " . self::V . " ([email protected])\n\n";
126        $footer = "\n";
127        $footer .= "-----END PHP CRYPTER BLOCK-----\n";
128        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
129        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
130        $key_size = mcrypt_get_key_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
131        $key = substr($this->key,0,$key_size);
132        
133        if( $this->decrypt ) 
134            $return = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($str), MCRYPT_MODE_ECB, $iv);
135        else {
136            $strings = str_split(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $str, MCRYPT_MODE_ECB, $iv)), 65);
137            foreach ( $strings as $string )
138                $data .= $string . "\n";
139            $return = $header . $data . $footer;
140        }
141        return $return;
142    }
143    
144    /**
145     * Human readable file size function
146     * @return string
147     */
148    function xfilesize($size) {
149        switch ( $size ) {
150            case $size > 1099511627776 :
151                $size = number_format($size / 1099511627776, 2, ".", ",") . " TB";
152            break;
153            case $size > 1073741824 :
154                $size = number_format($size / 1073741824, 2, ".", ",") . " GB";
155            break;
156            case $size > 1048576 :
157                $size = number_format($size / 1048576, 2, ".", ",") . " MB";
158            break;
159            case $size > 1024 :
160                $size = number_format($size / 1024, 2, ".", ",") . " kB";
161            break;
162            default :
163                $size = number_format($size, 2, ".", ",") . " Bytes";
164        }
165        return $size;
166    }
167    
168    /**
169     * Check target data
170     * @return bool. TRUE if file exists and readable.
171     */
172    function cekData ($file) {
173        if ( $this->verbose ) print "\n [*] Checking " . $file . " if it's exists..\n";
174        if ( !is_file($file) || !is_readable($file) )
175            return false;
176        else {
177            if ( $this->verbose )
178                print $this->crot(" [+] File " . $file . " is exists and readable..", 'l_green') . "\n";
179            return true;
180        }
181    }
182    
183    /**
184     * Read target data
185     * @return string.
186     */
187    function readData ($file) {
188        $msg = NULL;
189        $read = fopen($file, "r");
190        $msg .= fread($read, filesize($file));
191        if ( $this->verbose )
192            print " [*] File size is " . $this->xfilesize(filesize($file)) ."\n";
193        if ( $this->decrypt ) {
194            $msg = explode("\n\n", $msg);
195            $msg = str_replace("\n", '', $msg[1]);
196        }
197        fclose($read);
198        return $msg;
199    }
200    
201    /**
202     * Create file and and write data to the file.
203     * @return bool
204     */
205    function writeData ($file, $data) {
206        $fh = fopen($file, 'wx+');
207        fwrite($fh, $data);
208        fclose($fh);
209        if ( $this->verbose )
210            print $this->crot(" [*] Data has been writed to " . $file, 'l_green') . "\n";
211        return true;
212    }
213    
214    
215    /**
216     * Make UNIX like parameter command.
217     * This function from losbrutos and modified by earomero. Thankyou. =)
218     * @author losbrutos <[email protected]>
219     * @author earomero <[email protected]>
220     * @param array argv
221     * @return array
222     */
223    function arguments($argv) {
224        $_ARG = array();
225        foreach ($argv as $arg) {
226            if (preg_match('#^-{1,2}([a-zA-Z0-9]*)=?(.*)$#', $arg, $matches)) {
227                $key = $matches[1];
228                switch ($matches[2]) {
229                    case '':
230                    case 'true':
231                    $arg = true;
232                    break;
233                    case 'false':
234                    $arg = false;
235                    break;
236                    default:
237                    $arg = $matches[2];
238                }
239                
240                // make unix like -afd == -a -f -d
241                if(preg_match("/^-([a-zA-Z0-9]+)/", $matches[0], $match)) {
242                    $string = $match[1];
243                    for($i=0; strlen($string) > $i; $i++) {
244                        $_ARG[$string[$i]] = true;
245                    }
246                } else {
247                    $_ARG[$key] = $arg;    
248                }            
249            } else {
250                $_ARG['input'][] = $arg;
251            }        
252        }
253        return $_ARG;    
254    }
255    
256    /**
257     * Function to print colorful output to terminal.
258     * @param string    $string    String to be colored.
259     * @param string    $fontColor The available color
260     *        Available color :
261     *                  black, dark_gray, blue, green, l_green, cyan, l_cyan
262     *                  red, l_red, purple, l_purple, brown, yellow, l_gray,
263     *                  white.
264     * @return string
265     */
266    private function crot($string, $fontColor=NULL) {
267        switch ($fontColor) {
268            case 'black' : $color = '0;30'; break;
269            case 'dark_gray' : $color = '1;30'; break;
270            case 'blue' : $color = '0;34'; break;
271            case 'l_blue' : $color = '1;34'; break;
272            case 'green' : $color = '0;32'; break;
273            case 'l_green' : $color = '1;32'; break;
274            case 'cyan' : $color = '0;36'; break;
275            case 'l_cyan' : $color = '0;36'; break;
276            case 'red' : $color = '0;31'; break;
277            case 'l_red' : $color = '1;31'; break;
278            case 'purple' : $color = '0;35'; break;
279            case 'l_purple' : $color = '1;35'; break;
280            case 'brown' : $color = '0;33'; break;
281            case 'yellow' : $color = '1;33'; break;
282            case 'l_gray' : $color = '0;37'; break;
283            case 'white' : $color = '1;37'; break;
284        }
285        $colored_string = "";
286        $colored_string .= "\033[" . $color . "m";
287        $colored_string .=  $string . "\033[0m";
288        return $colored_string;
289    }
290}
291?>

Contoh exec.php :

1<?php
2set_time_limit(0);
3ini_set('memory_limit', '-1'); // use this for large data file
4require_once('phpCrypter.php');
5new phpCrypter($argv);
6?>
1Usage : file.php --file=[file] [option(s)]
2Option(s) :
3-d : Decrypt | -e : Encrypt (required)
4--key=[key] : passphrase key to encrypt / decrypt file
5-v : verbose mode, print all output to terminal
6-o : write output to [file].tpl

Contoh melakukan encrypt

1/home/dit/PHP-Crypter/exec.php --file=/home/dit/private.txt --key="RAHASIA" -evo

atau

1/home/dit/PHP-Crypter/exec.php -e -v -o --file=/home/dit/private.txt --key="RAHASIA"

Dari contoh command di atas :

dia akan mengenkripsi file private.txt pada direktori /home/dit dengan passphrase key RAHASIA lalu menuliskan hasil enkripsi ke file private.txt.tpl di direktori yg sama.

Contoh melakukan decrypt

1/home/dit/PHP-Crypter/exec.php --file=/home/dit/private.txt.tpl --key="RAHASIA" -dvo

atau

1/home/dit/PHP-Crypter/exec.php -d -v -o --file=/home/dit/private.txt.tpl --key="RAHASIA"

Dia akan mendekrip file private.txt.tpl pada direktori /home/dit dengan passphrase key RAHASIA lalu menuliskan hasil dekripsi ke file private.txt.tpl.tpl di direktori yg sama.

Note : Jika option “o” tidak di set maka dia akan menampilkan output ke terminal, bukan ke file.

TODO:

  • Ketika mengenkripsi file, dia akan membuat file baru dengan penambahan extension .tpl. Sedangkan akan lebih baik jika ketika mendekrip file akan kembali ke file extension semula.
  • Belum bisa mengetahui apakah file tersebut benar2 terdekrip atau tidak.