jordan_bethの日記: 教えて Perl の神さま! 2
Crypt::CBC でハマル。
あるテキストファイルを暗号化、必要なときに復号して使用したい、という要求のために Perl の Crypt::CBC を使ってスクリプトを書いたんだが、暗号化時か復号時にバッファに取り込んだ文字列を正常に書き出してもらえない、という現象に苦しんでいる。下はその検証用のソース。
----------------------------------------------------------------------------
#!/usr/bin/perl
$| = 1 ;
use Crypt::CBC ;
my( $cipher ) = Crypt::CBC->new
(
{
key => 'this is the key',
cipher => "Blowfish",
}
) ;
# 平文テキストを暗号化(test.txt を test.enc へ)
open( INFILE, "test.txt" ) ;
open( OUTFILE, "> test.enc" ) ;
$cipher->start('encrypting') ;
my( $buffer ) = "" ;
while( read( INFILE, $buffer, 1024 ) )
{
print( OUTFILE $cipher->crypt( $buffer ) ) ;
}
$cipher->finish() ;
close( INFILE ) ;
close( OUTFILE ) ;
# 暗号化ファイルを復号(test.enc を test.lst へ)
open( INFILE, "test.enc" ) ;
open( OUTFILE, "> test.lst" ) ;
$cipher->start( 'decrypting' ) ;
$buffer = "" ;
while( read( INFILE, $buffer, 1024 ) )
{
print( OUTFILE $cipher->crypt( $buffer ) ) ;
}
$cipher->finish() ;
close( INFILE ) ;
close( OUTFILE ) ;
exit() ;
--------------------------------------------------------------------------
テストに使用したテキストファイルは次のもの(test.txt)
--------------------------------------------------------------------------
This is test file for CBC encryption feature.
123456789+123456789+123456789+123456789+123456789+123456789+
============================================================
d6!w+&hzu<UJ)|cWanjQoE@19WRV{fX;oXE>F{mbhI7;J=8Cp0+8(!J72k6
|xMiI;[okb#IwHy+ugQ#]^^wGZ)JipQi&6^@u:.u1Z]wq3Q_|#aP*,'6dpg]
068c'GoMe0_&.f'NLN!('zx|B9^THq_H[PEy7FaQ.&/r>9O6MBiZ)+^'[yK+
4azy@an>3TC6UV^G!(]R?oZM_@uI]_!vo7V0QEmg.]@0LE=hS>TM3tv,rr
fR-*qM2z/L=<[x@AR[>(>P/;2/hd3p]7hn&P2ga&GPo/LH+ANtptiK=0Nw0k
WglK;VQT5/nkQe!Aj8,FH&qzL-c[#w0|0qtSjt40NT[4Ck5('ACRm@mz#&
tAu|6j#kFG+4t{_2n+GGw8#{H]s-C!!>2D=,Hsraql0QDC#)Ut=NOY^<
sbr{CrgpQ'{{'ZhdiZ*&nXX/<f[SIcg?wlK+Ng72@j;AWWJLD0KxOvB--p!
BEpxrk[7Wqa0}B(b:>5kJgO!qlu|FON?0Uw@,Bn&wlvC=0Vd5Wvu92(eMtqe
UKn>0pVAKzzdD'6aIA(:4K|M2X,-A|PFWgo.KML#0Jx@Poiw)*8@eKC{s?]
+8myXd@iNf}Frz_@@Xn@_.+5aMa#GV;5SiX+jZ.BjX;!]2U0)}369YMQj-(
?=yY#k[J7>vVFj]D53.}t@uGPdeS8ru6Ti98wFLypjk3T/;GGR_3#t>p(bR:
2@fkZ0'0mKK02:{'8o;(zSx/BplHYH#-JFS!'PoXVLibirN<IAKI7I-0Kq'L
n{]v+h;8(&[D>OG//sec[;]VRu/OaO;5J/,#hq>EP'g}Q'BBhWT+B[8H;Th
c.X7/Rl8|464Pgz:qB4H<N7Q:O3ztpE[2'j0G?b>ERevpImV]/W6yhXB){.[
eq)I+5_e13}Dr=et-T,fgLk65gjeI,>uRA3p7&uc9L#4V7}:r1Qh[;Ov5|X&
&*}J:VMJD8GRD9kJB};5F}>E:-zAVf1Fu}+Y;]N/Z?s,EWO'/igU6)u,lqeo
NKu2q4.1T;=;MP-T&z*?ohF2=@XvgeC,dEf0E/HY(Jz>d8:)T0.RB7A^:HoQ
ToOk1Z2.SVD'rY)6cWo7u?Z*sQ*G1YI5E?^L^mU9}(lx:MAtu^]WU4yB&1q
80QbDHI^[j>d9^q=Meo;a/B+>c4LvetK3H^Kg+5,MHi91-OIo_aKpN}ZUT,
0#.E3P2&t7FM8w#1txjJ;x;<^Q|cC31#!bqP99?kzl1'2D<Sn]^9)^r>Sk:|
l}{2=T8.:ekEF2e:8h,#4m2#.M7;yWR.U(CyStl.,YB/yYUk{Z2?cW=c4vA
JV8]:Z>ip5,raj9tNalFqLSW^g!b]F'VZnW0pQ21@}+b=?2AY9&_;@:5D-V
Etwd*-Zk/S5'y?b7q1x)YT*hXH^!mS#kwNVKJ4WXut&zHIo3.E|R.[=ak)X
x|9cNdegJ:>{g)0c@STZ]xs&({0c]_&;0(>:lVG1wT;{^sU0U^@I.I!d<,X
9L+P|HZRw]M,P8E{zTo>Nwj8NtV10#xZSx.|eK1OLe?W:kq{m(SAp@Xs(+kE
Cru&x?HQZ&/aB9,;4s1gj|&7r.9.U[-FMY,tI0wv70g2.0&BPNG,BsN1e4
sR7lm=Lu@nR9*WfL_WBkWtY@HlZ;=2p0f=KBTfWW,+.8@,Xa:c=ey{>t9jp
/>O_)6('L(?y7hni>LOq#1_c?,jLsj>TBQbU6-Nu:6wF}rH+ox,!jp];t[xZ
Rv<nPWP*f(:lbZH)terT5('3EA9,mEpJX}OL7w>,wiN*R.fh0geIKg2b}xu>
============================================================
123456789+123456789+123456789+123456789+123456789+123456789+
###################### End OF LINE #########################
----------------------------------------------------------------------------
最終的に出力された復号ファイル(test.lst)
----------------------------------------------------------------------------
This is test file for CBC encryption feature.
123456789+123456789+123456789+123456789+123456789+123456789+
============================================================
d6!w+&hzu<UJ)|cWanjQoE@19WRV{fX;oXE>F{mbhI7;J=8Cp0+8(!J72k6
|xMiI;[okb#IwHy+ugQ#]^^wGZ)JipQi&6^@u:.u1Z]wq3Q_|#aP*,'6dpg]
068c'GoMe0_&.f'NLN!('zx|B9^THq_H[PEy7FaQ.&/r>9O6MBiZ)+^'[yK+
4azy@an>3TC6UV^G!(]R?oZM_@uI]_!vo7V0QEmg.]@0LE=hS>TM3tv,rr
fR-*qM2z/L=<[x@AR[>(>P/;2/hd3p]7hn&P2ga&GPo/LH+ANtptiK=0Nw0k
WglK;VQT5/nkQe!Aj8,FH&qzL-c[#w0|0qtSjt40NT[4Ck5('ACRm@mz#&
tAu|6j#kFG+4t{_2n+GGw8#{H]s-C!!>2D=,Hsraql0QDC#)Ut=NOY^<
sbr{CrgpQ'{{'ZhdiZ*&nXX/<f[SIcg?wlK+Ng72@j;AWWJLD0KxOvB--p!
BEpxrk[7Wqa0}B(b:>5kJgO!qlu|FON?0Uw@,Bn&wlvC=0Vd5Wvu92(eMtqe
UKn>0pVAKzzdD'6aIA(:4K|M2X,-A|PFWgo.KML#0Jx@Poiw)*8@eKC{s?]
+8myXd@iNf}Frz_@@Xn@_.+5aMa#GV;5SiX+jZ.BjX;!]2U0)}369YMQj-(
?=yY#k[J7>vVFj]D53.}t@uGPdeS8ru6Ti98wFLypjk3T/;GGR_3#t>p(bR:
2@fkZ0'0mKK02:{'8o;(zSx/BplHYH#-JFS!'PoXVLibirN<IAKI7I-0Kq'L
n{]v+h;8(&[D>OG//sec[;]VRu/OaO;5J/,#hq>EP'g}Q'BBhWT+B[8H;Th
c.X7/Rl8|464Pgz:qB4H<N7Q:O3ztpE[2'j0G?b>ERevpImV]/W6yhXB){.[
eq)I+5_e13}Dr=et-T,fgLk65gjeI,>uRA3p7&uc9L#4V7}:r1Qh[;Ov5|X&
&*}J:VMJD8GRD9kJB};5F}>E:-zAVf1Fu}+Y;]N/Z?s,EWO'/igU6)u,lqeo
NKu2q4.1T;=;MP-T&z*?ohF2=@XvgeC,dEf0E/HY(Jz>d8:)T0.RB7A^:HoQ
ToOk1Z2.SVD'rY)6cWo7u?Z*sQ*G1YI5E?^L^mU9}(lx:MAtu^]WU4yB&1q
80QbDHI^[j>d9^q=Meo;a/B+>c4LvetK3H^Kg+5,MHi91-OIo_aKpN}ZUT,
0#.E3P2&t7FM8w#1txjJ;x;<^Q|cC31#!bqP99?kzl1'2D<Sn]^9)^r>Sk:|
l}{2=T8.:ekEF2e:8h,#4m2#.M7;yWR.U(CyStl.,YB/yYUk{Z2?cW=c4vA
JV8]:Z>ip5,raj9tNalFqLSW^g!b]F'VZnW0pQ21@}+b=?2AY9&_;@:5D-V
Etwd*-Zk/S5'y?b7q1x)YT*hXH^!mS#kwNVKJ4WXut&zHIo3.E|R.[=ak)X
x|9cNdegJ:>{g)0c@STZ]xs&({0c]_&;0(>:lVG1wT;{^sU0U^@I.I!d<,X
9L+P|HZRw]M,P8E{zTo>Nwj8NtV10#xZSx.|eK1OLe?W:kq{m(SAp@Xs(+kE
Cru&x?HQZ&/aB9,;4s1gj|&7r.9.U[-FMY,tI0wv70g2.0&BPNG,BsN1e4
sR7lm=Lu@nR9*WfL_WBkWtY@HlZ;=2p0f=KBTfWW,+.8@,Xa:c=ey{>t9jp
/>O_)6('L(?y7hni>LOq#1_c?,jLsj>TBQbU6-Nu:6wF}rH+ox,!jp];t[xZ
Rv<nPWP*f(:lbZH)terT5('3EA9,mEpJX}OL7w>,wiN*R.fh0geIKg2b}xu>
============================================================
123456789+123456789+123456789+123456789+123456789+123456789+
###################### End OF LINE ###########
------------------------------------------------------------------------------
暗号化か復号時のループの最後で取得した $buffer の crypt() がうまくいっておらず、その文がゴッソリ抜けているかんじ。
ストリームのバッファリング関連かと思って $|=1 するもダメ。
問題の切り分けのために、暗号化せず $buffer をそのまま出力するのはオッケーなので、やはり crypt() が怪しいような気がする。
しょうがないので、ファイル読み込みを小分けにせず、ファイル全体を $buffer に溜め込んで
$cipher->encrypt() と $cipher->decrypt() を使って一括暗号化・復号して問題を回避。こちらは正常な動作だ。
でも、これでは大きなファイルを暗号化するためには使用できないのが痛いなー
Perl の神様。迷える子スクリプターに救いの手を。
いいかげんですみません (スコア:0)
暗号化はあまり詳しくないので間違いだったら申し訳ないのですが。
この前Perlとjavaで自前で実装したのですが、
CBCの暗号化はソースが公開されていて
それを元に実装すると、自然とこうなるようです。
(改造すると、既存のモノが複合できなくなるからそのまま?)
CBCは32byte(128bit)単位で暗号化(と複合)をするのですが、
それに満たない長さの場合にデータが化けたり壊れたりするようです。
ですので、自前実装には、32byteに満たない分は0x00を埋めて、複合の後に削除する。
という変な回避策を取りました。(その時はこういう実装でよい場合だったので)
ちなみに自分の場合は
test.txt(27byte)=>test.enc(32byte) 余計なデータがついてる?
test.enc(32byte)=>test.lst(32byte) ごみデータが最後につく
という状態でした。
Re:いいかげんですみません (スコア:1)
[いのる]
○ [感謝する]
[逃げる]
AC な神様、コメントどーもです。
うーむ。手軽に暗号化モジュールを使いたいのに、そこらへんモジュールのほうで責任もって処理して欲しいところですが…。
どーしようー、と思って perldoc Crypt::CBC で確認中...
まー、ここら辺なんだろうなぁ、フムフム…(しばし読み続ける... )
あぁぁぁぁぁぁ finish() に文字が返ってるぅぅう!crypt() で出力し切れなかった内部バッファは finsih() で拾ってあげなきゃいけないようです。
※教訓 飾りじゃないのyo perldoc は
ということで、先の検証用のスクリプトは
----------------------------------------------------------------------------------------------------------------
$ diff test.txt test.lst
$
--------------------------------------------------------
ということでした。南無。
ん? 俺、今何か言った?