BlowFishで復号化のみするには?

解決


ラン  2005-08-12 05:26:43  No: 17005

https://www.petitmonte.com/bbs/answers?question_id=2555
https://www.petitmonte.com/bbs/answers?question_id=2593

過去の質問にもいくつか有るようですが、
BlowFishで、復号化する為に必要なSizeの求め方が
分かりません。

以下のようにしてもエラーになるか、復号化文字列の末尾が化けたりします。

Size := Length(Src);
SetLength(Dst, Size);
Size := Decode(Src[1], Dst[1], Size);

何か勘違いしてるかもしれませんが、
宜しくお願いします。


メラトニン  2005-08-12 07:56:43  No: 17006

//dst:暗号化されたString型(サイズが分かってる)
//src:複合化されたString型
Size := Decode(dst[1], src[1], Length(dst));
SetLength(src, Size);
Edit1.text:=src;


メラトニン  2005-08-12 08:00:26  No: 17007

送信してしまった…
BlowFishって今日はじめてみたのですが、暗号化された値はstring型で扱うとまずそうです。(#0を含むため)
stringは動作確認程度にして実際に暗号化されたデータを扱うにはbyte配列を使うべきかと思います。


メラトニン  2005-08-12 08:07:40  No: 17008

ああっ!修正
//dst:暗号化されたString型(サイズが分かってる)
//src:複合化されたString型
SetLength(src, OutputSize(Length(dst))); //足りなかった
Size := Decode(dst[1], src[1], Length(dst));
SetLength(src, Size);
Edit1.text:=src;


メラトニン  2005-08-12 11:33:08  No: 17009

テキストのみを扱いやすいようにBase64エンコードかけてみました。
使い方はこんな感じです。
usesにBF2B64Textを追加して
テキストを暗号化Base64テキスト出力
   Edit2.text:=BF2B64Encode('PAI',Edit1.Text,$31415926535);
暗号化Base64をテキストをテキスト出力
   Edit1.text:=BF2B64decode('PAI',Edit2.Text,$31415926535);

BF2B64Text.pas
unit BF2B64Text;
////////////////////////////////////////////////////////////////////////////////
// 文字列をBlowFishで復号化しBase64エンコードで保存する関数
// base64は 「FDELPHI」 の"base64、エンコード&デコード"を使用
// http://forum.nifty.com/fdelphi/samples/01327.html
// 著作:河邦 正 氏
//
// これを利用するにはBlowFishユニットが必要
// BlowFishユニット
// http://kuma.webj.net/
// 著作:t_kumagai 氏
//
// BlowFishのアルゴリズム
// 著作:Bruce Schneier 氏
////////////////////////////////////////////////////////////////////////////////
interface

uses
  SysUtils, Windows, Classes, BlowFish, CryptUtils;

  function BF2B64Encode(key,Text:string; IV:Int64):string;
  function BF2B64Decode(key,Text:string; IV:Int64):string;

implementation

// 3バイト分のバイトオーダーを修正する(Kylixでは不要のはず)
function exchange_0_2(Src: DWORD): DWORD;
type
  TTemp = array[0..3]of BYTE;
begin
  Result := Src;
  TTemp(Result)[2] := TTemp(Src)[0];
  TTemp(Result)[0] := TTemp(Src)[2];
end;

// StreamからSizeバイトを読み込み、エンコードした文字列を返す
function base64encode(Stream: TStream; Size: Integer): string;
const
  Table: PChar =
    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
var
  Buffer, Src: Pointer;
  Dst: PChar;
  I: Integer;

  procedure doNbyte(N: Integer);
  var
    Value: DWORD;
    I: Integer;
  begin
    if not(N in [1..3]) then Exit;
    Value := 0;
    // SrcからNバイトをValueに読み込む
    Move(PBYTE(Src)^, Value, N);
    // バイトオーダーを修正(Kylixでは不要のはず)
    Value := exchange_0_2(Value);
    // Srcの読み込み位置を進める
    Inc(Integer(Src), N);
    // 6ビットずつエンコード×4回
    for I := 3 downto 0 do
    begin
      if I > N then
        Dst[I] := '=' // 変換しない分は‘=’でパディングする
      else
        Dst[I] := Table[Value and $3f];
      Value := Value shr 6;
    end;
    // 次の書き込み位置にする
    Inc(Integer(Dst), 4);
  end;

begin
  Buffer := AllocMem(Size);
  try
    Size := Stream.Read(PBYTE(Buffer)^, Size);
    // エンコード後の文字列の長さにする
    SetLength(Result, (Size + 2) div 3 * 4);
    if Size > 0 then
    begin
      // 読み込み元のポインタ
      Src := Buffer;
      // 書き込み先のポインタ
      Dst := PChar(Result);
      // 3バイトずつ書き込む
      for I := 0 to Size div 3 - 1 do
        doNbyte(3);
      if (Size mod 3) > 0 then
        doNbyte(Size mod 3);
    end;
  finally
    FreeMem(Buffer);
  end;
end;

// TextをデコードしてStreamに書き込み、書き込んだバイト数を返す
function base64decode(Stream: TStream; Text: string): Integer;
var
  Src: PChar;
  I: Integer;

  // 各文字を6ビットデータに変換する
  function decode(code: BYTE): BYTE;
  begin
    case Char(code) of
    'A'..'Z': Result := code - BYTE('A');
    'a'..'z': Result := code - BYTE('a') + 26;
    '0'..'9': Result := code - BYTE('0') + 52;
    '+': Result := 62;
    '/': Result := 63;
    else Result := 0; // ‘=’の場合も‘0’を返す
    end;
  end;

  function doNbyte: Integer;
  var
    I, N: Integer;
    Value: DWORD;
  begin
    // パディング文字‘=’の有無を調べる
    N := 3; // デコード後のバイト数をNにセット
    for I := 2 to 3 do
    begin
      if Src[I] = '=' then
      begin
        N := I - 1;
        break;
      end;
    end;
    // 4文字をデコードする
    value := 0;
    for I := 0 to 3 do
    begin
      // 1文字を6ビットに変換×4回
      Value := Value shl 6;
      Inc(Value, decode(PBYTE(Src)^));
      Inc(Integer(Src));
    end;
    // バイトオーダーを修正(Kylixでは不要のはず)
    Value := exchange_0_2(Value);
    // デコードしたデータの書き込み
    Result := Stream.Write(Value, N);
  end;

begin
  Result := 0;
  Src := PChar(Text);
  // 4文字ずつデコード
  for I := 0 to (Length(Text) div 4) - 1 do
    // 書き込んだバイト数をResultにカウントする
    Inc(Result, doNbyte);
end;

//テキストをエンコードしてBase64テキストを返す
function BF2B64Encode(key,Text:string; IV:Int64):string;
var
  Crypt : TCryptCBC;
  Stream:TMemoryStream;
  Size,i  :integer;
  dst  : array of byte;
begin
  try
    Crypt:= TCryptCBC.Create(Key, TBlowFish.Create, IV, SizeOf(IV), pmStandard);
    size := Length(Text);
    SetLength(dst, Crypt.OutputSize(Size));
    Size := Crypt.Encode(Text[1], dst[0], Size);

    stream:= TMemoryStream.Create;
    stream.Size:= size;
    stream.Seek(0,soFromBeginning);
    for i:=0 to size-1 do
      stream.Write(dst[i],1);
    stream.Seek(0,soFromBeginning);
    Result:=base64encode(stream,Size);
  finally
    stream.Free;
    Crypt.Free;
  end;
end;

//Base64テキストを出コードしてテキストを返す
function BF2B64Decode(key,Text:string; IV:Int64):string;
var
  Crypt : TCryptCBC;
  Stream:TMemoryStream;
  Size,size2,i  :integer;
  dst,src  : array of byte;
  bufstr : string;
begin
  try
    stream:= TMemoryStream.Create;
    size:=base64decode(stream,Text);

    stream.Seek(0,soFromBeginning);
    setLength(dst,size);
    for i:=0 to size-1 do
      stream.read(dst[i],1);

    Crypt:= TCryptCBC.Create(Key, TBlowFish.Create, IV, SizeOf(IV), pmStandard);
    size2 := Crypt.OutputSize(Size);
    SetLength(src,size2);
    size2 := Crypt.Decode(dst[0], src[0], Size);
    for i:=0 to size2-1 do
      result:= result + char(src[i]);
  finally
    stream.Free;
    Crypt.Free;
  end;
end;

end.


ラン  2005-08-12 18:47:48  No: 17010

メラトニンさん、早々のご回答有難う御座います。
BF2B64Textを使用して、暗号化・復号化することができました。
有難う御座いました。

ただ、2つほど質問が有るんですけど。

1.Base64にもう一度暗号化する理由はあるんでしょうか?。
もしかして、BlowFishで暗号化されたものは、
うまくテキスト出力されないとかでしょうか?。(byte配列で、と言われてたので。)
私が作成するのは、最終的に暗号化したものをファイル出力する予定です。

2.BF2B64Textの第三引数(IV)の'$31415926535'は何を示しているのでしょうか?
第一引数はキーワード、第二引数は暗号・復号化文字列だと思いますけど。

度々、質問で申し訳ありませんが、宜しくお願いします。


メラトニン  2005-08-13 04:09:15  No: 17011

勝手ながら「テキスト→テキスト」を解釈していました。
だって、Src[1], Dst[1]って配列1からアクセスしていたもんですから。
1.Base64は暗号化ではありません、バイナリデータをASCII化するための処理です。テキスト→ファイル、ファイル→テキストであればbase64化する必要はありません。
2.適当な初期ベクトルです。値を変えると別の暗号が生まれます。てかこれはBlowFish暗号化の原理ですので…


メラトニン  2005-08-13 04:33:04  No: 17012

こんな感じでどうでしょう

function BFstr2File(key,Text,path:string; IV:Int64):boolean;
var
  Crypt : TCryptCBC;
  Stream: TFileStream;
  Size,i  :integer;
  dst  : array of byte;
begin
result:=True;
Crypt:= TCryptCBC.Create(Key, TBlowFish.Create, IV, SizeOf(IV), pmStandard);
stream:= TFileStream.Create(path,fmCreate);
try
    size := Length(Text);
    SetLength(dst, Crypt.OutputSize(Size));
    Size := Crypt.Encode(Text[1], dst[0], Size);

    stream.Size:= size;
    stream.Seek(0,soFromBeginning);
    for i:=0 to size-1 do
      stream.Write(dst[i],1);
finally
  stream.Free;
  Crypt.Free;
end;

end;

function BFFile2str(key,path:string; IV:Int64):string;
var
  Crypt : TCryptCBC;
  Stream:TFileStream;
  Size,size2,i  :integer;
  dst,src  : array of byte;
begin
    stream:= TFileStream.Create(path,fmOpenRead  );
    Crypt:= TCryptCBC.Create(Key, TBlowFish.Create, IV, SizeOf(IV), pmStandard);
  try
    size:=stream.Size;
    stream.Seek(0,soFromBeginning);
    setLength(dst,size);
    for i:=0 to size-1 do
      stream.read(dst[i],1);

    size2 := Crypt.OutputSize(Size);
    SetLength(src,size2);
    size2 := Crypt.Decode(dst[0], src[0], Size);
    for i:=0 to size2-1 do
      result:= result + char(src[i]);
  finally
    stream.Free;
    Crypt.Free;
  end;
end;


ラン  2005-08-17 19:10:46  No: 17013

メラトニンさん、返事遅くなり申し訳ありません。

2点の質問のご回答有難う御座いました。
Base64はてっきり暗号化とばかり思ってました。
いろいろ勉強になりました。
有難う御座いました。


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

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






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