Blowfishの使い方

解決


昔から犬  2008-10-08 22:34:46  No: 32149

テキストフィールドの値を暗号化/復号化したくて
別スレで教えていただいた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を押しても何も出力されません。
根本的な勘違いをしてるような気がするのですが
原因をご教示いただきたく、よろしくお願いいたします。


ofZ  2008-10-09 00:01:26  No: 32150

以下の二点かな?

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の第三引数は、暗号化・復号化したあとのバッファサイズじゃなく、
暗号化・復号化すべきバッファのサイズと思われる。


鯖雄  2008-10-09 01:18:01  No: 32151

>oftさん
前スレからお付き合いいただいてありがとうございます。

>Size := Decode(Src[1], Dst[1], Length(Src));
一応Encodeのほうは、その2行前でLengthを取っています。
しかし、Decodeのほうは、Lengthを使うとCryptUtilsのDecodeの
Assertでエラーが発生します。
    Assert(Size mod BlockSize = 0);

何を入れればいいのやら・・・


昔から犬  2008-10-09 01:19:55  No: 32152

>鯖雄さん
鯖雄さんは名前を間違えました。
昔から犬と同一人物です。


Manbon  2008-10-09 01:24:55  No: 32153

良くは見てませんが、ここは参考になりませんか?
https://www.petitmonte.com/bbs/answers?question_id=2555


Manbon  2008-10-09 01:27:01  No: 32154

あと、ここにサンプルがありました。
http://kuma.webj.net/


ttt  2008-10-09 01:33:38  No: 32155

Encodeした結果のサイズは OutputSize(Size)
で、これはBlockSizeの倍数になっているはずなので、
本来はそのままDecodeに渡せば問題はないはずです。

> Assertでエラーが発生します。

ということは、Length(Decodeしようとしている文字列)≠Length(Encodeされた文字列) ということです。
例によって、EditBoxを経由したために文字が化けているのではないでしょうか。
Encodeの前と後、Decodeの前と後それぞれで(EditBoxで目視確認するのではなく)実際の変数の中身、サイズがそれぞれどうなっているか調べてみましたか?


昔から犬  2008-10-09 02:35:55  No: 32156

>Manbonさん
わざわざ探していただいて、ありがとうございます。
そのスレは事前にチェックしたのですが、確かにEncodeとDecodeを
一箇所で行う場合は問題ありませんでした。
それを分割した場合にSizeに問題があってダメなんだろうなあ、という
漠然とした感じです。

>tttさん
Encodeした結果のサイズをグローバル変数で保持して、Decodeで使ってみました。
Decode後の戻り値がとてもおかしい。
ここから辿ってみたいと思います。
ありがとうございました。


ofZ  2008-10-09 03:40:02  No: 32157

アーカイブに含まれるサンプルを見てテストしたけど、これで動いた。

      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になりました。


昔から犬  2008-10-09 03:59:40  No: 32158

>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;
---------------------------


ofZ  2008-10-09 07:02:28  No: 32159

XPMan 貼り付けとかしていない?


原因はEdit  2008-10-09 17:06:04  No: 32160

>   Src := Edit1.Text;
Decordの際にエラーになるのは、既に指摘されてるように、
Editに入れた文字列を使って復号してることに原因がある。
  '1234567'
  'abcdef'
  '暗号化'
  'よろしく'
  '昔から犬'
これら↑を暗号化した文字列をEditに入れると、その末尾の
表示不可キャラクタ(1Byte)が欠落する。
そのため、Edit1.Textの文字列からDecodeするとAssertエラーで落ちる。
MemoやEditに入れた表示不可キャラクタがどう処理されるかは OSによって
少し違うけど。


ofZ  2008-10-09 17:37:50  No: 32161

> その末尾の表示不可キャラクタ(1Byte)が欠落する。
Edit に入れる前後で、16進表示するようにしたところ、
「表示不可キャラクタで」欠落することを確認しました。
当方では、偶然欠落しない文字列の甘いテストしていたわけですね。
失礼しました。


昔から犬  2008-10-09 19:22:13  No: 32162

>原因は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した文字列をグローバルで保持することで
キレイに動作するようになりました。

ご協力いただいたみなさん、ほんとうにありがとうございました。


昔から犬(実装報告)  2008-10-10 23:17:52  No: 32163

後で見る方のために、アプリに実装してみて「あらら?」っていうことを書いておきます。

実装時に上記のルーチンをfunction化しました。
Editの文字列を暗号化してレジストリへ書き込み、必要時にレジストリから
復号化して読み出そうとしたわけですが、復号時にさんざん見飽きたエラーが発生しました。

調べてみると、レジストリから読み出した値のLengthがEncodeしたものより
1つだけ長くなっています。
原因は私の残り少ない脳細胞では判りません。

対症療法として、TRegistryをすべてTInifileにしてやるとOKでした。

以上、ご参考まで。


原因は同じ  2008-10-10 23:32:48  No: 32164

上でもさんざん言われているように、暗号化したデータが正当な文字列である保証なんてないんだから(動いたとしてもそれはたまたま)
バイナリとして保存するなり、可読な文字列に符号化するなりしないと……


昔から犬  2008-10-11 01:50:06  No: 32165

>原因は同じさん
できました!・・・ような気がする。

暗号化後にBase64エンコードして書き込み。
読み込み時は復号化前にBase64デコードした後で復号化。
これで正解ですか?
ってことは、これでレジストリでも何でも関係ないってことかorz

ほんとうに、ありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加