星期六, 12月 12, 2009

簡單的文字檔編碼

文件資料通常需要作一些加密處理,避免一眼就能看清楚文件的內容,然後再用相同的方式作解密文件。我們用範例程式碼來說明一下幾個簡單的文件資料編碼方式。
  • 1對1字元交換方式
  • 0xFF 的 XOR 字元 運算方式
  • 字元移位方式



第一種:1對1字元交換方式。這一種的方式如同 PHP的str_rot13的函式一樣,為固定的英文字母作交換。下面範例是用PHP實作 str_rot13的方式:


<?php
class String1
{
    
// 搜尋字元組
    
public static $rot13_from "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    
// 替換字元組
    
public static $rot13_to   "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM";
    
public static function encode ($str)
    {
        
preg_match_all('/[a-zA-Z]/'self::$rot13_from$rot13_search_array);
        
preg_match_all('/[a-zA-Z]/'self::$rot13_to$rot13_replace_array);
        
// 組合成陣列 array('a' => 'n', 'b' => 'o' .... 的陣列
        
$tr array_combine($rot13_search_array[0], $rot13_replace_array[0]);
        
// 轉換資料
        
return strtr($str$tr);
    }
    
public static function decode ($str)
    {
        return 
self::encode($str);
    }
}
$str "PHP: Hypertext Preprocessor";
echo 
str_rot13($str);
echo 
"\r\n";
echo 
$rot13 String1::encode($str);
echo 
"\r\n";
echo 
str_rot13($rot13);
echo 
"\r\n";
echo 
String1::decode($rot13);
?>


我們可以再String1 這個類別內的encode方法,看到使用 preg_match_all 用正規表示式將定義的固定字串的字元抓取到陣列內,並且再使用array_combine 將兩陣列組合成為一個索引值和資料值對應的陣列。如所引值為 a 那麼對應的值為 n,所引值為 b 那麼其對應的值為 o。之後用 strtr 這個函式將字串依照陣列定義作資料轉換。
上面範例的輸出結果:
CUC: Ulcregrkg Cercebprffbe


CUC: Ulcregrkg Cercebprffbe

PHP: Hypertext Preprocessor
PHP: Hypertext Preprocessor
這個觀念可以延伸到0x00 - 0xff 字元作成對應表,再將資料作轉換也可以。


第二種:0xFF 的 XOR 字元 運算方式。其實只是個簡單運算,如將 0x01 作一下和0xFF的 XOR 運算,那麼得到的結果為0xFE,反之0xFE再作一次 0xFF的XOR 運算則得到 0x01的值。
下面這個範例程式則是將所有的字元都作了一下0xFF的XOR 運算。

<?php
class String2
{
    
public static function encode ($str)
    {
        
$len strlen($str);
        for (
$i 0$i $len$i ++) {
            
$word .= chr(ord($str[$i]) ^ 0xff);
        }
        return 
$word;
    }
    
public static function decode ($str)
    {
        return 
self::encode($str);
    }
}
$str "PHP: Hypertext Preprocessor";
echo 
$str String2::encode($str);
echo 
"\r\n";
echo 
String2::decode($str);
?>


輸出結果:
窈級葽????蒍?????


PHP: Hypertext Preprocessor

其實這個應用並不是只有對0xFF作XOR運算,而是用資料最大字元,這邊使用0xFF是因為所有字元最大的是0xFF,而再設計時,可以稍為調整一下,會得到不一樣的結果。


第三種:字元移位方式。這個方式其實是將字元值往前推或往後推幾位數。如將 a 往前推兩位則變為c,b則便為d。下面的程式範例則是依照這個觀念設計:

<?php
class String3
{
    
private static $shift 0x02;
    
public static function encode ($str "")
    {
        
$len strlen($str);
        for (
$i 0$i $len$i ++) {
            
$chr ord($str[$i]);
            
$chr = ($chr self::$shift 0xff)
                 ? 
$chr self::$shift 0xff
                 
$chr self::$shift;
            
$word .= chr($chr);
        }
        return 
$word;
    }
    
public function decode ($str)
    {
        
$len strlen($str);
        for (
$i 0$i $len$i ++) {
            
$chr ord($str[$i]);
            
$chr = ($chr self::$shift 0x00)
                 ? 
$chr self::$shift 0xff
                 
$chr self::$shift;
            
$word .= chr($chr);
        }
        return 
$word;
    }
}
$str "PHP: Hypertext Preprocessor";
echo 
"\r\n";
echo 
$str String3::encode($str);
echo 
"\r\n";
echo 
String3::decode($str);
?>


這個範例是字元往前移動的範例,我們可以看到 String3這個類別內的encode這個方法作了一些處理,當字元移位後值超過0xFF,則減掉0xFF,而再decode反解時,則是低於0x00時,要往後開始算。

範例的執行結果:
RJR<"J{rgtvgzv"Rtgrtqeguuqt


PHP: Hypertext Preprocessor


其實整個程式反之可以將String3:decode 當編碼用,而將String3:encode當解碼用。這樣就是將位元往後移的方式。

粗略寫了三個固定字元的編碼方式,希望這篇能讓學弟了解一下加密基礎。但加密也不一定是固定字元的方式。

舉個簡單的例子:將0xFF這個字元作一下位元位移運算子運算,如 0xFF << 0x02 則資料便成0x3FC。但是如果用 0x3FC >> 0x02 則資料又變成0xFF。

總而言之,這些基礎可以交錯應用,就可以作出自己訂的文件加解密規則囉。

沒有留言:

張貼留言

我的意見