D05:ファイルを複合化する

ファイルを暗号化した場合、元のデータに戻すには、複合化を行わなければなりません。
今回は、ファイルを複合化するようなCGIを紹介します。
「D04:ファイルを暗号化する」で暗号化したファイルを複合化します。

ファイルを開く

解説
#!/usr/local/bin/perl
プロバイダがPerlを置いている場所を記述します。
ここでは/usr/local/bin/perlにあるとしています。
require "Blowfish_PP.pm";
Blowfishというライセンスフリーの複合化モジュールを利用します。
☆今回のポイント☆
複合化にはライセンスフリーモジュールを利用しよう!
$max=2;
送られてくるデータの数を$maxに代入しています。
データはファイル以外も可能です。
$size=$ENV{'CONTENT_LENGTH'};
送られてきたデータのサイズを$sizeに代入しています。
ただし、複数のデータが決まったフォーマットに従ってまとめて送られてくる為、実際にはデータ本体以外の部分も合わせたサイズになっています。
if($size>1024*1024){
  exit;
}
送られてきたデータのサイズが1MBより大きい場合にはプログラムを終了しています。
送られてきたデータがあまりにも大き過ぎると色々と不都合があるので、ここでは1MBに制限しています。
binmode(STDIN);
送られてくるファイルの種類を特に決めていないので、バイナリデータとして扱う為にbinmode(STDIN)を書いています。
while($size){
  $len=sysread(STDIN, $buf, $size);
  if($len==0){
    last;
  }
  $size=$size-$len;
  $data=$data.$buf;
}
送られてきたデータを$dataに代入しています。
$x=index($data,"\r\n");
$cut=substr($data,0,$x);
$cut="\r\n".$cut;
複数のデータが送られてくる場合、特定の文字列で区切られています。
その区切りの文字列を$cutに代入しています。
for($i=0;$i<$max;$i++){
  $x=index($data,"\r\n\r\n")+4;
  $filename[$i]=substr($data,0,$x);
  $filename[$i]=~s/\n//g;
  $filename[$i]=~s/.*filename="//;
  $filename[$i]=~s/".*//;
  $filename[$i]=~s/.*\\//g;
  $filename[$i]=~s".*/""g;
  $y=length($data);
  $data=substr($data,$x,$y-$x);
  $x=index($data,$cut);
  $y=length($data);
  $file[$i]=substr($data,0,$x);
  $data=substr($data,$x+2,$y-$x-2);
}
$maxの数だけ送られてきたデータを$file[xx]に代入しています。
データがファイルの場合はファイル名が$filename[xx]に代入されます。
xxに入る数字は0〜$max-1の数字になります。
binmode(STDOUT);
出力するデータをバイナリ形式で扱うのでbinmode(STDOUT)を書いています。
print "Content-type:application/octet-stream\n";
print "Content-Disposition:attachment;filename=d_$filename[1]\n\n";
出力するデータがダウンロードする形式である事を出力します。
$key_in="12345678" . $file[0];
$change=new Crypt::Blowfish_PP($key_in);
キーは8バイト以上必要なので、入力が空だった場合でも複合化できるように、12345678という文字列を先頭に追加しています。
$key_inをキーとして複合化する準備として$changeを作成しています。
@data_in=unpack("C*",$file[1]);
送られてきたデータを1バイト単位の配列にしています。
$loop=int(($#data_in+1)/8);
$data_out="";
for($i=0;$i<$loop;$i++){
  $data_block="";
  for($j=0;$j<8;$j++){
    $data_block=$data_block . pack("C",$data_in[$i*8+$j]);
  }
  $data_out=$data_out . $change->decrypt($data_block);
}
$loopで複合化する回数を計算しています。
複合化は8バイトずつ行います。
@data_max=unpack("C*",$data_out);
複合化したデータを1バイト単位の配列にしています。
$len=$#data_max+1;
for($i=$#data_max;$i>=0;$i--){
  if($data_max[$i]==$data_max[$#data_max]){
    $len=$len-1;
  }else{
    last;
  }
}
暗号化した際にデータの最後にダミーデータを追加しているので、どこまでがダミーデータかを調べて$lenに代入しています。
for($i=0;$i<$len;$i++){
  print pack("C",$data_max[$i]);
}
データを出力しています。
exit;
プログラムを終了させます。