テキストフィールドの値を暗号化/復号化したくて
別スレで教えていただいたBlowfishを試しています。
サンプルを元に暗号化はそれらしいものが出力されたのですが
復号化がどうにもうまくいきません。
---------------------------
implementation
uses Blowfish, CryptUtils;
{$R *.dfm}
//暗号化
procedure TForm1.Button1Click(Sender: TObject);
const
Key = 'ABCDEFG';
IV: array [0..1 - 1] of Int64 = ($1234567890123456);
var
Src, Dst: string;
Size: Integer;
begin
Src := Edit1.Text;
with (TCryptCBC.Create(Key, TBlowFish.Create, IV, SizeOf(IV), pmStandard)) do
try
Size := Length(Src);
SetLength(Dst, OutputSize(Size));
Size := Encode(Src[1], Dst[1], Size);
SetLength(Dst, Size);
Edit1.Text := Dst;
finally
Free;
end;
end;
//復号化
procedure TForm1.Button2Click(Sender: TObject);
const
Key = 'ABCDEFG';
IV: array [0..1 - 1] of Int64 = ($1234567890123456);
var
Src, Dst: string;
Size: Integer;
begin
Src := Edit1.Text;
with (TCryptCBC.Create(Key, TBlowFish.Create, IV, SizeOf(IV), pmStandard)) do
try
Size := OutputSize(Length(Src));
SetLength(Dst, Size);
Size := Decode(Src[1], Dst[1], Size);
SetLength(Dst, Size);
Edit2.Text := Dst;
finally
Free;
end;
end;
---------------------------
この場合、ボタン2を押しても何も出力されません。
根本的な勘違いをしてるような気がするのですが
原因をご教示いただきたく、よろしくお願いいたします。
以下の二点かな?
Size := Encode(Src[1], Dst[1], Size);
↓
Size := Encode(Src[1], Dst[1], Length(Src));
Size := Decode(Src[1], Dst[1], Size);
↓
Size := Decode(Src[1], Dst[1], Length(Src));
Encode, Decodeの第三引数は、暗号化・復号化したあとのバッファサイズじゃなく、
暗号化・復号化すべきバッファのサイズと思われる。
>oftさん
前スレからお付き合いいただいてありがとうございます。
>Size := Decode(Src[1], Dst[1], Length(Src));
一応Encodeのほうは、その2行前でLengthを取っています。
しかし、Decodeのほうは、Lengthを使うとCryptUtilsのDecodeの
Assertでエラーが発生します。
Assert(Size mod BlockSize = 0);
何を入れればいいのやら・・・
>鯖雄さん
鯖雄さんは名前を間違えました。
昔から犬と同一人物です。
良くは見てませんが、ここは参考になりませんか?
https://www.petitmonte.com/bbs/answers?question_id=2555
あと、ここにサンプルがありました。
http://kuma.webj.net/
Encodeした結果のサイズは OutputSize(Size)
で、これはBlockSizeの倍数になっているはずなので、
本来はそのままDecodeに渡せば問題はないはずです。
> Assertでエラーが発生します。
ということは、Length(Decodeしようとしている文字列)≠Length(Encodeされた文字列) ということです。
例によって、EditBoxを経由したために文字が化けているのではないでしょうか。
Encodeの前と後、Decodeの前と後それぞれで(EditBoxで目視確認するのではなく)実際の変数の中身、サイズがそれぞれどうなっているか調べてみましたか?
>Manbonさん
わざわざ探していただいて、ありがとうございます。
そのスレは事前にチェックしたのですが、確かにEncodeとDecodeを
一箇所で行う場合は問題ありませんでした。
それを分割した場合にSizeに問題があってダメなんだろうなあ、という
漠然とした感じです。
>tttさん
Encodeした結果のサイズをグローバル変数で保持して、Decodeで使ってみました。
Decode後の戻り値がとてもおかしい。
ここから辿ってみたいと思います。
ありがとうございました。
アーカイブに含まれるサンプルを見てテストしたけど、これで動いた。
Size := OutputSize(Length(Src));
SetLength(Dst, Size);
Size := Encode(Src[1], Dst[1], Length(Src));
SetLength(Dst, Size);
Edit1.Text := Dst;
Size := OutputSize(Length(Src));
SetLength(Dst, Size);
Size := Decode(Src[1], Dst[1], Length(Src));
SetLength(Dst, Size);
Edit2.Text := Dst;
Editに"漢字"を入力して、実行し、OutputSize=8, Encode結果も8
さらに変換してOutputSize=16,Decodeの結果が4になりました。
>oftさん
ありがとうございます。
やはりDecode時にCryptUtilsのAssertで落ちました。
何が違うのか・・・少し頭を冷やします。
---------------------------
procedure TForm1.Button1Click(Sender: TObject);
const
Key = 'ABCDEFG';
IV: array [0..1 - 1] of Int64 = ($1234567890123456);
var
Size: Integer;
Src, Dst: string;
begin
Src := Edit1.Text;
with (TCryptCBC.Create(Key, TBlowFish.Create, IV, SizeOf(IV), pmStandard)) do
try
Size := OutputSize(Length(Src));
SetLength(Dst, Size);
Size := Encode(Src[1], Dst[1], Length(Src));
SetLength(Dst, Size);
Edit1.Text := Dst;
finally
Free;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
const
Key = 'ABCDEFG';
IV: array [0..1 - 1] of Int64 = ($1234567890123456);
var
Size: Integer;
Src, Dst: string;
begin
Src := Edit1.Text;
with (TCryptCBC.Create(Key, TBlowFish.Create, IV, SizeOf(IV), pmStandard)) do
try
Size := OutputSize(Length(Src));
SetLength(Dst, Size);
Size := Decode(Src[1], Dst[1], Length(Src));
SetLength(Dst, Size);
Edit2.Text := Dst;
finally
Free;
end;
end;
---------------------------
XPMan 貼り付けとかしていない?
> Src := Edit1.Text;
Decordの際にエラーになるのは、既に指摘されてるように、
Editに入れた文字列を使って復号してることに原因がある。
'1234567'
'abcdef'
'暗号化'
'よろしく'
'昔から犬'
これら↑を暗号化した文字列をEditに入れると、その末尾の
表示不可キャラクタ(1Byte)が欠落する。
そのため、Edit1.Textの文字列からDecodeするとAssertエラーで落ちる。
MemoやEditに入れた表示不可キャラクタがどう処理されるかは OSによって
少し違うけど。
> その末尾の表示不可キャラクタ(1Byte)が欠落する。
Edit に入れる前後で、16進表示するようにしたところ、
「表示不可キャラクタで」欠落することを確認しました。
当方では、偶然欠落しない文字列の甘いテストしていたわけですね。
失礼しました。
>原因はEditさん
ご指摘のとおりでした。
上でtttさんにもご指摘いただきながらちゃんと検証できてなかったです。
「同じstringだからいいじゃん」という考えが甘かったようです。
>oftさん
大変お手間を取らせました。
ほんとうに助かりました。
-----------------------------------
implementation
uses Blowfish, CryptUtils;
var
BeforEncode, AfterEncode: Integer;
EncodedStr: string;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
const
Key = 'ABCDEFG';
IV: array [0..1 - 1] of Int64 = ($1234567890123456);
var
Src: string;
begin
Src := Edit1.Text;
BeforEncode := Length(Edit1.Text);
with (TCryptCBC.Create(Key, TBlowFish.Create, IV, SizeOf(IV), pmStandard)) do
try
SetLength(EncodedStr, OutputSize(BeforEncode));
AfterEncode := Encode(Src[1], EncodedStr[1], BeforEncode);
Edit1.Text := EncodedStr;
finally
Free;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
const
Key = 'ABCDEFG';
IV: array [0..1 - 1] of Int64 = ($1234567890123456);
var
Src, Decoded: string;
Size: Integer;
begin
Src := EncodedStr;
SetLength(Src, AfterEncode);
SetLength(Decoded, AfterEncode);
with (TCryptCBC.Create(Key, TBlowFish.Create, IV, SizeOf(IV), pmStandard)) do
try
Size := Decode(Src[1], Decoded[1], AfterEncode);
SetLength(Decoded, Size);
Edit2.Text := Decoded;
finally
Free;
end;
end;
-----------------------------------
Encodeした文字列をグローバルで保持することで
キレイに動作するようになりました。
ご協力いただいたみなさん、ほんとうにありがとうございました。
後で見る方のために、アプリに実装してみて「あらら?」っていうことを書いておきます。
実装時に上記のルーチンをfunction化しました。
Editの文字列を暗号化してレジストリへ書き込み、必要時にレジストリから
復号化して読み出そうとしたわけですが、復号時にさんざん見飽きたエラーが発生しました。
調べてみると、レジストリから読み出した値のLengthがEncodeしたものより
1つだけ長くなっています。
原因は私の残り少ない脳細胞では判りません。
対症療法として、TRegistryをすべてTInifileにしてやるとOKでした。
以上、ご参考まで。
上でもさんざん言われているように、暗号化したデータが正当な文字列である保証なんてないんだから(動いたとしてもそれはたまたま)
バイナリとして保存するなり、可読な文字列に符号化するなりしないと……
>原因は同じさん
できました!・・・ような気がする。
暗号化後にBase64エンコードして書き込み。
読み込み時は復号化前にBase64デコードした後で復号化。
これで正解ですか?
ってことは、これでレジストリでも何でも関係ないってことかorz
ほんとうに、ありがとうございました。
ツイート | ![]() |